#ifndef PLAYER_H
#define PLAYER_H
#include "card.h"
#define MAX_NAME_LEN 11
#define MAX_DRAW_CARD 11
#define MAX_CHIPS 999999999
/**
* @brief ゲーム結果の状態
*
* 1回のゲームで起こりうる結果を表す列挙型。
*/
typedef enum
{
GameWin = 1, /**< プレイヤーの勝ち */
GameDraw = 2, /**< ディーラーとの引き分け */
GameLose = 3, /**< プレイヤーの負け */
GameBlackJack = 4, /**< ブラックジャックでの勝ち */
GameSurrender = 5, /**< サレンダー(降り)*/
GameNone = 0 /**< ゲーム未終了 */
} GameStatus;
/**
* @brief プレイヤー構造体
*
* プレイヤーの手札、賭け金、ゲームの状態など全ての情報を保持する。
* 通常の手札とスプリット(分割)手札の両方に対応。
*/
typedef struct
{
char name[MAX_NAME_LEN]; /**< プレイヤーの表示名 */
long chips; /**< 現在のチップ数 */
int isBot; /**< コンピュータプレイヤーかどうか */
int surrendered; /**< サレンダーしたかどうか */
Card hand[MAX_DRAW_CARD]; /**< メインの手札 */
int handSize; /**< メイン手札のカード枚数 */
int handValue; /**< メイン手札の合計値 */
long bet; /**< メイン手札への賭け金 */
GameStatus lastGame; /**< メイン手札の結果 */
Card splitHand[MAX_DRAW_CARD]; /**< スプリット手札 */
int splitHandSize; /**< スプリット手札のカード枚数 */
int splitHandValue; /**< スプリット手札の合計値 */
long splitBet; /**< スプリット手札への賭け金 */
GameStatus splitLastGame; /**< スプリット手札の結果 */
int hasSplit; /**< スプリットしたかどうか */
} Player;
/**
* @brief ボット用のランダムな名前を選択
*
* @return const char* 定義済みリストからランダムに選んだ名前
*/
const char *chooseRandomName();
/**
* @brief ディーラーの初期化
*
* ディーラーの初期状態を設定し、名前を"Dealer"に設定する。
*
* @param player ディーラーとして初期化するプレイヤー構造体
*/
void initDealer(Player *player);
/**
* @brief ボットプレイヤーの初期化
*
* コンピュータ制御のプレイヤーをランダムな名前と初期チップで設定する。
*
* @param player 初期化するプレイヤー構造体
* @param initChips 初期チップ数
*/
void initBot(Player *player, const int initChips);
/**
* @brief 人間プレイヤーの初期化
*
* 人間プレイヤーを指定された名前と初期チップで設定する。
*
* @param player 初期化するプレイヤー構造体
* @param initChips 初期チップ数
* @param name プレイヤーの表示名
*/
void initPlayer(Player *player, const int initChips, const char *name);
/**
* @brief ダブルダウン可能か確認
*
* プレイヤーが十分なチップを持っており、手札が適切な状態か確認する。
*
* @param player 確認するプレイヤー
* @param split スプリット手札を確認するかどうか
* @return int 可能なら1、不可能なら0
*/
int canDoubleDown(const Player *player, const int split);
/**
* @brief サレンダー可能か確認
*
* プレイヤーが最初のターンで2枚の手札を持っているか確認する。
*
* @param player 確認するプレイヤー
* @return int 可能なら1、不可能なら0
*/
int canSurrender(const Player *player);
/**
* @brief サレンダーの処理
*
* 賭け金の半額を返却し、プレイヤーをサレンダー状態にする。
*
* @param player サレンダーするプレイヤー
*/
void processSurrender(Player *player);
/**
* @brief 賭け金の設定
*
* プレイヤーからチップを差し引き、賭け金として設定する。
*
* @param player 賭けを行うプレイヤー
* @param amount 賭け金額
* @param split スプリット手札への賭けかどうか
* @return int 成功なら1、チップ不足なら0
*/
int placeBet(Player *player, const long amount, const int split);
/**
* @brief メイン手札にカードを追加
*
* カードを追加し、手札の合計値を更新する。
*
* @param player カードを受け取るプレイヤー
* @param card 追加するカード
*/
void addCardToHand(Player *player, const Card card);
/**
* @brief スプリット手札にカードを追加
*
* カードを追加し、スプリット手札の合計値を更新する。
*
* @param player カードを受け取るプレイヤー
* @param card 追加するカード
*/
void addCardToSplitHand(Player *player, const Card card);
/**
* @brief スプリット可能か確認
*
* プレイヤーが十分なチップを持っており、同じランクの2枚のカードを
* 持っているか確認する。
*
* @param player 確認するプレイヤー
* @return int 可能なら1、不可能なら0
*/
int canSplit(const Player *player);
/**
* @brief スプリットの処理
*
* 手札を2つに分け、それぞれに同額の賭け金を設定する。
*
* @param player スプリットを行うプレイヤー
*/
void processSplit(Player *player);
/**
* @brief 手札の価値を計算
*
* ブラックジャックのルールに従って手札の合計値を計算する。
* エースを1または11として適切に扱う。
*
* @param hand カードの配列
* @param handSize カードの枚数
* @return int 手札の合計値
*/
int calculateHandValue(const Card hand[MAX_DRAW_CARD], const int handSize);
/**
* @brief ゲーム結果の表示
*
* 勝敗結果を適切な形式で表示する。
*
* @param player 結果を表示するプレイヤー
* @param split スプリット手札の結果を表示するかどうか
*/
void printLastGame(const Player *player, const int split);
#endif