prg-lang-2 / final / BlackJack / player.c
player.c
Raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "player.h"
#include "game.h"

static const char *NAMES[20] = {
    "Alice", "Alex", "Bob", "Charlie", "David", "Eve",
    "Frank", "Grace", "Jack", "Karen", "Mia", "Noah",
    "Thomas", "Wendy", "Daniel", "Henry", "Amelia",
    "Lily", "Emma", "James"};

const char *chooseRandomName()
{
    return NAMES[rand() % 20];
}

void initDealer(Player *player)
{
    strncpy(player->name, "Dealer", MAX_NAME_LEN - 1);
    player->name[MAX_NAME_LEN - 1] = '\0';
    player->chips = 0;
    player->isBot = 1;
    player->bet = 0;
    player->handSize = 0;
    player->handValue = 0;
    player->lastGame = GameNone;
}

void initBot(Player *player, const int initChips)
{
    strncpy(player->name, chooseRandomName(), MAX_NAME_LEN - 1);
    player->name[MAX_NAME_LEN - 1] = '\0';
    player->chips = initChips;
    player->isBot = 1;
    player->surrendered = 0;
    player->bet = 0;
    player->handSize = 0;
    player->handValue = 0;
    player->lastGame = GameNone;
}

void initPlayer(Player *player, const int initChips, const char *name)
{
    strncpy(player->name, name, MAX_NAME_LEN - 1);
    player->name[MAX_NAME_LEN - 1] = '\0';
    player->chips = initChips;
    player->isBot = 0;
    player->surrendered = 0;
    player->bet = 0;
    player->handSize = 0;
    player->handValue = 0;
    player->lastGame = GameNone;
    player->splitBet = 0;
    player->splitHandSize = 0;
    player->splitHandValue = 0;
    player->splitLastGame = GameNone;
}

int canDoubleDown(const Player *player, const int split)
{
    if (split)
    {
        return player->splitBet <= player->chips && player->splitHandSize == 2;
    }
    return player->bet <= player->chips && player->handSize == 2;
}

int canSurrender(const Player *player)
{
    return !player->hasSplit && player->handSize == 2;
}

void processSurrender(Player *player)
{
    player->surrendered = 1;
    player->chips += player->bet / 2;
    player->bet = 0;
}

int placeBet(Player *player, const long amount, const int split)
{
    if (amount > player->chips)
    {
        return 0;
    }
    if (split)
    {
        player->splitBet += amount;
    }
    else
    {
        player->bet += amount;
    }
    player->chips -= amount;
    // チップが上限を超えないように調整
    if (player->chips > MAX_CHIPS)
    {
        player->chips = MAX_CHIPS;
    }
    return 1;
}

void addCardToHand(Player *player, const Card card)
{
    player->hand[player->handSize++] = card;
    player->handValue = calculateHandValue(player->hand, player->handSize);
}

void addCardToSplitHand(Player *player, const Card card)
{
    player->splitHand[player->splitHandSize++] = card;
    player->splitHandValue = calculateHandValue(player->splitHand, player->splitHandSize);
}

int canSplit(const Player *player)
{
    return !player->hasSplit && player->bet <= player->chips && player->handSize == 2 &&
           (player->hand[0].rank == player->hand[1].rank || (player->hand[0].rank >= 10 && player->hand[1].rank >= 10));
}

void processSplit(Player *player)
{
    player->hasSplit = 1;
    player->splitBet = player->bet;
    player->chips -= player->bet;
    // 2枚目のカードをスプリット手札に移動
    player->splitHand[0] = player->hand[1];
    player->splitHandSize = 1;
    player->splitHandValue = calculateHandValue(player->splitHand, player->splitHandSize);
    // 元の手札を1枚にする
    player->handSize = 1;
    player->handValue = calculateHandValue(player->hand, player->handSize);
}

int calculateHandValue(const Card hand[MAX_DRAW_CARD], const int handSize)
{
    // 手札の合計値を計算
    int value = 0;
    // エースの枚数をカウント(後で1か11の判定に使用)
    int aces = 0;

    // まずエースを11として計算
    for (int i = 0; i < handSize; i++)
    {
        int rank = hand[i].rank;
        if (rank == 1)
        {
            aces++;
            value += 11;
        }
        else if (rank > 10)
        {
            value += 10;
        }
        else
        {
            value += rank;
        }
    }

    // バーストしている場合、エースを1として再計算
    while (value > 21 && aces > 0)
    {
        value -= 10; // エースを11から1に変更(-10)
        aces--;
    }
    return value;
}

void printLastGame(const Player *player, const int split)
{
    const GameStatus *gs = split ? &player->splitLastGame : &player->lastGame;
    switch (*gs)
    {
    case GameBlackJack:
        printf("\033[47m\033[31mB\033[30mJ\033[39m\033[49m");
        break;
    case GameWin:
        printf("Win");
        break;
    case GameDraw:
        printf("Draw");
        break;
    case GameLose:
        printf("Lose");
        break;
    case GameSurrender:
        printf("Surr");
        break;
    default:
        break;
    }
}