#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include "player.h"
#include "util.h"
void initPlayers(Game *game, const int initChips, const int playerCount, const int botCount)
{
// プレイヤー数の設定(人間プレイヤー + ボット)
game->playerCount = playerCount + botCount;
initDealer(&game->dealer);
game->players = (Player *)malloc(game->playerCount * sizeof(Player));
int *indices = (int *)malloc(game->playerCount * sizeof(int));
for (int i = 0; i < game->playerCount; i++)
{
indices[i] = i;
}
// プレイヤーの順番をランダムにシャッフル
for (int i = game->playerCount - 1; i > 0; i--)
{
int j = rand() % (i + 1);
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}
for (int i = 0; i < game->playerCount; i++)
{
if (indices[i] < playerCount)
{
char defaultName[MAX_NAME_LEN];
snprintf(defaultName, MAX_NAME_LEN, "User%.2d", (indices[i] + 1) % 100);
initPlayer(&game->players[i], initChips, defaultName);
}
else
{
initBot(&game->players[i], initChips);
}
}
free(indices);
}
void initGame(Game *game)
{
initDeck(game->deck);
shuffleDeck(game->deck);
game->deckIndex = 0;
initDealer(&game->dealer);
for (int i = 0; i < game->playerCount; i++)
{
game->players[i].surrendered = 0;
game->players[i].bet = 0;
game->players[i].handSize = 0;
game->players[i].handValue = 0;
game->players[i].splitBet = 0;
game->players[i].splitHandSize = 0;
game->players[i].splitHandValue = 0;
game->players[i].hasSplit = 0;
}
}
Card drawCard(Game *game)
{
return game->deck[game->deckIndex++];
}
void displayTitle()
{
int startX = (getTerminalWidth() - 52) / 2;
if (startX < 1)
startX = 1;
printf("\033[2J\033[H");
printf("\033[1m\033[47m");
printf("\033[2;%dH", startX);
printf("\033[31m ____ _ _ ");
printf("\033[30m _ _ ");
printf("\033[3;%dH", startX);
printf("\033[31m | _ \\| | | | ");
printf("\033[30m | | | | ");
printf("\033[4;%dH", startX);
printf("\033[31m | |_) | | __ _ ___| | __ ");
printf("\033[30m | | __ _ ___| | __ ");
printf("\033[5;%dH", startX);
printf("\033[31m | _ <| |/ _` |/ __| |/ / ");
printf("\033[30m _ | |/ _` |/ __| |/ / ");
printf("\033[6;%dH", startX);
printf("\033[31m | |_) | | (_| | (__| < ");
printf("\033[30m| |__| | (_| | (__| < ");
printf("\033[7;%dH", startX);
printf("\033[31m |____/|_|\\__,_|\\___|_|\\_\\ ");
printf("\033[30m \\____/ \\__,_|\\___|_|\\_\\ ");
printf("\033[8;%dH", startX);
printf("\033[31m ");
printf("\033[30m ");
printf("\033[39m\033[49m\033[0m");
printf("\033[10;1H");
fflush(stdout);
}
void _displayBoard(const Game *game, const int init, const int status, const int playerIndex, const char playerAction, const int splitAction)
{
// プレイヤー人数に応じて表示幅を計算
int contentWidth = 20 * game->playerCount;
// ディーラーの手札表示(初期状態では2枚目以降は裏向き)
int startX = (getTerminalWidth() - contentWidth) / 2;
if (startX < 1)
startX = 1;
printf("\033[2J\033[H");
printf("\033[1;%dH", startX + (contentWidth - 20) / 2);
printf("%s", game->dealer.name);
printf("\033[2;%dH", startX + (contentWidth - 20) / 2);
for (int i = 0; i < game->dealer.handSize; i++)
{
if (init == 1 && i != 0)
{
printCardBack();
}
else
{
printCard(game->dealer.hand[i]);
}
printf(" ");
}
// プレイヤーの表示
for (int i = 0; i < game->playerCount; i++)
{
int x = 4;
int y = startX + (i * 20);
printf("\033[%d;%dH", x, y);
if (game->players[i].bet > 0)
{
printf("[%ld]", game->players[i].bet);
}
else
{
printf("[]");
}
if (game->players[i].hasSplit)
{
printf("\033[%d;%dH", x, y + 9);
if (game->players[i].splitBet > 0)
{
printf("[%ld]", game->players[i].splitBet);
}
else
{
printf("[]");
}
}
for (int j = 0; j < game->players[i].handSize; j++)
{
if (game->players[i].hasSplit && j % 2 == 0)
{
printf("\033[%d;%dH", x + 1 + (j / 2), y);
}
else if (!game->players[i].hasSplit && j % 4 == 0)
{
printf("\033[%d;%dH", x + 1 + (j / 4), y);
}
else
{
printf(" ");
}
printCard(game->players[i].hand[j]);
}
if (game->players[i].hasSplit)
{
for (int j = 0; j < game->players[i].splitHandSize; j++)
{
if (j % 2 == 0)
{
printf("\033[%d;%dH", x + 1 + (j / 2), y + 9);
}
else
{
printf(" ");
}
printCard(game->players[i].splitHand[j]);
}
}
printf("\033[%d;%dH", x + 3, y);
if (game->players[i].isBot)
{
printf("%s (%ld)", game->players[i].name, game->players[i].chips);
}
else
{
printf("\033[4m%s\033[0m (%ld)", game->players[i].name, game->players[i].chips);
}
if (status)
{
for (int t = 0; t <= game->players[i].hasSplit; t++)
{
printf("\033[%d;%dH", x + 4, y + 9 * t);
printLastGame(&game->players[i], t);
}
}
else
{
if (playerIndex == i)
{
printf("\033[%d;%dH", x + 4, y + splitAction * 9);
if (playerAction == 'H' || playerAction == 'h')
{
printf("Hit");
}
else if (playerAction == 'D' || playerAction == 'd')
{
printf("Double");
}
else if (playerAction == 'R' || playerAction == 'r')
{
printf("Surr");
}
else
{
printf("Stand");
}
}
}
}
printf("\033[10;1H");
fflush(stdout);
}
void displayBoard(const Game *game, const int init)
{
_displayBoard(game, init, 0, -1, 'n', 0);
}
void displayStatus(const Game *game)
{
_displayBoard(game, 0, 1, -1, 'n', 0);
}
void displayAction(const Game *game, const int playerIndex, char action, int split)
{
_displayBoard(game, 1, 0, playerIndex, action, split);
}
void _processBet(Game *game, Player *player, GameStatus *lastGame, long *bet, const int handValue, const int handSize, const double bjRate)
{
// サレンダーの場合の処理
if (player->surrendered)
{
*lastGame = GameSurrender;
}
// ディーラーがバーストした場合の処理
else if (game->dealer.handValue > 21)
{
if (handValue <= 21)
{
// ブラックジャック(21で2枚)の場合は高配当
if (handValue == 21 && handSize == 2)
{
*lastGame = GameBlackJack;
player->chips += (long)(*bet * (bjRate + 1.0));
printf("SYSTEM> %s won. %ld chips back.\n", player->name, (long)(*bet * 2.5));
}
else
{
*lastGame = GameWin;
player->chips += *bet * 2;
printf("SYSTEM> %s won. %ld chips back.\n", player->name, *bet * 2);
}
}
else
{
*lastGame = GameLose;
printf("SYSTEM> %s lose.\n", player->name);
}
}
// ディーラーがバーストしなかった場合の処理
else
{
if (
handValue > 21 ||
game->dealer.handValue > handValue)
{
*lastGame = GameLose;
printf("SYSTEM> %s lose.\n", player->name);
}
else if (game->dealer.handValue < handValue)
{
if (handValue == 21 && handSize == 2)
{
*lastGame = GameBlackJack;
player->chips += (long)(*bet * 2.5);
printf("SYSTEM> %s won. %ld chips back.\n", player->name, (long)(*bet * 2.5));
}
else
{
*lastGame = GameWin;
player->chips += *bet * 2;
printf("SYSTEM> %s won. %ld chips back.\n", player->name, *bet * 2);
}
}
else
{
*lastGame = GameDraw;
player->chips += *bet;
printf("SYSTEM> %s is draw. %ld chips back.\n", player->name, *bet);
}
}
*bet = 0;
}
void processBet(Game *game, Player *player, const double bjRate)
{
_processBet(game, player, &player->lastGame, &player->bet, player->handValue, player->handSize, bjRate);
}
void processSplitBet(Game *game, Player *player, const double bjRate)
{
_processBet(game, player, &player->splitLastGame, &player->splitBet, player->splitHandValue, player->splitHandSize, bjRate);
}
int processAction(Game *game, const int playerIndex, const int split, const char action)
{
Player *player = &game->players[playerIndex];
// Hit
if (action == 'H' || action == 'h')
{
addCardToHand(player, drawCard(game));
displayAction(game, playerIndex, action, split);
if (player->handValue > 21)
{
printf("SYSTEM> %s busted!\n", player->name);
return 1;
}
}
// Split
else if ((action == 'P' || action == 'p') && canSplit(player))
{
processSplit(player);
displayAction(game, playerIndex, action, 0);
csleep(0.5);
addCardToHand(player, drawCard(game));
displayAction(game, playerIndex, action, 0);
csleep(0.5);
addCardToSplitHand(player, drawCard(game));
displayAction(game, playerIndex, action, 0);
}
// Double Down
else if ((action == 'D' || action == 'd') && canDoubleDown(player, split))
{
if (split)
{
placeBet(player, player->splitBet, split);
addCardToSplitHand(player, drawCard(game));
}
else
{
placeBet(player, player->bet, split);
addCardToHand(player, drawCard(game));
}
displayAction(game, playerIndex, action, split);
if (player->handValue > 21)
{
printf("SYSTEM> %s busted!\n", player->name);
}
return 1;
}
// Surrender
else if ((action == 'R' || action == 'r') && canSurrender(player))
{
processSurrender(player);
displayAction(game, playerIndex, action, split);
printf("SYSTEM> %s surrendered.\n", player->name);
csleep(1);
return 1;
}
// Stand
else if (action == 'S' || action == 's')
{
displayAction(game, playerIndex, action, split);
csleep(1);
return 1;
}
else
{
printf("SYSTEM> Invalid call\n");
return 0;
}
return 0;
}