#include #include #include #include #include "game.h" #include "card.h" #include "player.h" #include "util.h" #include "config.h" #define BUFFER_SIZE 256 char *ENTER_GREETINGS[3] = {"Hi", "Hello", "Hey"}; char *LEAVE_GREETINGS[3] = {"Damn it", "Good bye", "Bye"}; int main() { // 乱数の初期化 srand((unsigned int)time(NULL)); displayTitle(); if (getTerminalHeight() < 10) { fprintf(stderr, "Error: Terminal height is too small. Please adjust the terminal height.\n"); return 1; } Config *config = loadConfig("config.txt"); if (config == NULL) { fprintf(stderr, "Error: Failed to load config file 'config.txt'\n"); return 1; } int playerCount, botCount; long initChips, minBets, maxBets; double bjRate; int botDoubleDownMin, botDoubleDownMax, botDoubleDownRate; int botHitSoftRate, botHitMiddleRate, botHitHardRate; if ( getConfigValueInt(config, "player_count", &playerCount) || getConfigValueInt(config, "bot_count", &botCount) || getConfigValueLong(config, "init_chips", &initChips) || getConfigValueLong(config, "min_bets", &minBets) || getConfigValueLong(config, "max_bets", &maxBets) || getConfigValueDouble(config, "bj_rate", &bjRate) || getConfigValueInt(config, "bot_double_down_min", &botDoubleDownMin) || getConfigValueInt(config, "bot_double_down_max", &botDoubleDownMax) || getConfigValueInt(config, "bot_double_down_rate", &botDoubleDownRate) || getConfigValueInt(config, "bot_hit_soft_rate", &botHitSoftRate) || getConfigValueInt(config, "bot_hit_middle_rate", &botHitMiddleRate) || getConfigValueInt(config, "bot_hit_hard_rate", &botHitHardRate)) { fprintf(stderr, "Error: Invalid value in config file\n"); return 1; } #ifdef _WIN32 if (playerCount < 0 || botCount < 0 || (playerCount + botCount) > 4 || (playerCount + botCount) < 1) { fprintf(stderr, "Error: Player count must be 0-4 and total players must not exceed 4\n"); return 1; } #else const int maxPlayerCount = getTerminalWidth() / 20; if (playerCount < 0 || botCount < 0 || (playerCount + botCount) > maxPlayerCount || (playerCount + botCount) < 1) { fprintf(stderr, "Error: Player count must be 0-%d and total players must not exceed %d. Please adjust the terminal width.\n", maxPlayerCount, maxPlayerCount); return 1; } #endif if (initChips <= 0 || minBets <= 0 || maxBets <= 0 || minBets > maxBets || initChips < minBets || initChips > MAX_CHIPS || maxBets > MAX_CHIPS) { fprintf(stderr, "Error: The chip settings are invalid\n"); return 1; } if (bjRate < 1.0) { fprintf(stderr, "Error: Black Jack rate is invalid\n"); } if (botDoubleDownMin < 0 || botDoubleDownMax < 0 || botDoubleDownMin > botDoubleDownMax || botDoubleDownMax > 13 || botDoubleDownRate < 0 || botDoubleDownRate > 100 || botHitSoftRate < 0 || botHitSoftRate > 100 || botHitMiddleRate < 0 || botHitMiddleRate > 100 || botHitHardRate < 0 || botHitHardRate > 100) { fprintf(stderr, "Error: Bot settings are invalid\n"); return 1; } Game game; initPlayers(&game, initChips, playerCount, botCount); // プレイヤー名の設定 for (int i = 0; i < game.playerCount; i++) { // プレイヤーの場合は名前入力を受け付ける if (!game.players[i].isBot) { for (;;) { printf("Enter name for Player %d (or press Enter to keep %s): ", i + 1, game.players[i].name); char buffer[BUFFER_SIZE]; if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) { printf("SYSTEM> Invalid input!\n"); continue; } if (buffer[0] == '\n') { break; } buffer[strcspn(buffer, "\n")] = 0; size_t len = strlen(buffer); if (len == 0) { printf("SYSTEM> Name cannot be empty!\n"); continue; } if (len >= MAX_NAME_LEN) { printf("SYSTEM> Name is too long! Maximum %d characters.\n", MAX_NAME_LEN - 1); continue; } strncpy(game.players[i].name, buffer, MAX_NAME_LEN - 1); game.players[i].name[MAX_NAME_LEN - 1] = '\0'; break; } } else { printf("%s> %s\n", game.players[i].name, ENTER_GREETINGS[rand() % 3]); csleep(0.5); } } // ゲームのメインループ for (;;) { initGame(&game); // ベット額の設定 for (int i = 0; i < game.playerCount; i++) { if (!game.players[i].isBot) { printf("SYSTEM> %ld Minimum, %ld Maximum\n", minBets, maxBets); printf("SYSTEM> %s have %ld chips.\n", game.players[i].name, game.players[i].chips); printf("Dealer> Place your bet.\n"); long bet; for (;;) { printf("%s> I bet ", game.players[i].name); char buffer[BUFFER_SIZE]; if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) { continue; } char *tole; bet = strtol(buffer, &tole, 10); while (*tole == ' ' || *tole == '\n' || *tole == '\r') tole++; if (*tole != '\0') { printf("SYSTEM> Invalid chips!\n"); continue; } if (bet < minBets || bet > maxBets) { printf("SYSTEM> Invalid chips!\n"); continue; } if (!placeBet(&game.players[i], bet, 0)) { printf("SYSTEM> %s don't have enough chips!\n", game.players[i].name); continue; } break; } displayBoard(&game, 1); printf("SYSTEM> %s bet %ld chips.\n", game.players[i].name, bet); } else { // Botのベット額を計算(100単位でランダムに設定) long botBet = (rand() % ((min(game.players[i].chips, maxBets) - minBets) / 100 + 1)) * 100 + minBets; placeBet(&game.players[i], botBet, 0); displayBoard(&game, 1); printf("SYSTEM> %s bet %ld chips.\n", game.players[i].name, botBet); } csleep(0.5); } printf("Dealer> No more bets.\n"); csleep(1); // カードを配る for (int i = 0; i < 2; i++) { for (int j = 0; j < game.playerCount; j++) { addCardToHand(&game.players[j], drawCard(&game)); displayBoard(&game, 1); csleep(0.5); } addCardToHand(&game.dealer, drawCard(&game)); displayBoard(&game, 1); csleep(1); } // プレイヤーの行動 for (int i = 0; i < game.playerCount; i++) { if (!game.players[i].isBot) { for (int split = 0; split < 2; split++) { for (;;) { if (canSurrender(&game.players[i])) { if (canSplit(&game.players[i])) { printf("Dealer> (H)it, (D)ouble, S(p)lit, Su(r)render or (S)tand?\n%s> ", game.players[i].name); } else if (canDoubleDown(&game.players[i], split)) { printf("Dealer> (H)it, (D)ouble, Su(r)render or (S)tand?\n%s> ", game.players[i].name); } else { printf("Dealer> (H)it, Su(r)render or (S)tand?\n%s> ", game.players[i].name); } } else if (canDoubleDown(&game.players[i], split)) { printf("Dealer> (H)it, (D)ouble or (S)tand?\n%s> ", game.players[i].name); } else { printf("Dealer> (H)it or (S)tand?\n%s> ", game.players[i].name); } char buffer[BUFFER_SIZE]; if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) { continue; } if (processAction(&game, i, split, buffer[0])) { break; } } if (!game.players[i].hasSplit) { break; } } } else { for (;;) { char action = 's'; // Botの行動決定ロジック // ディーラーが強いカード(10以上またはA)を持っていて、自分の手札が16の場合はサレンダー if (game.players[i].handValue == 16 && canSurrender(&game.players[i])) { if (game.dealer.hand[0].rank >= 10 || game.dealer.hand[0].rank == 1) { action = 'r'; } } if (action == 's' && canDoubleDown(&game.players[i], 0)) { int decision = rand() % 100; if (game.players[i].handValue <= botDoubleDownMax && game.players[i].handValue >= botDoubleDownMin && decision < botDoubleDownRate) { action = 'd'; } } if (action == 's') { int decision = rand() % 100; if (game.players[i].handValue <= 12 && decision < botHitSoftRate) { action = 'h'; } else if (game.players[i].handValue <= 16 && decision < botHitMiddleRate) { action = 'h'; } else if (game.players[i].handValue <= 18 && decision < botHitHardRate) { action = 'h'; } } if (processAction(&game, i, 0, action)) { break; } csleep(1); } csleep(1); } } displayBoard(&game, 0); csleep(1); // ディーラーの行動(17以上になるまでヒット) while (game.dealer.handValue <= 16) { addCardToHand(&game.dealer, drawCard(&game)); displayBoard(&game, 0); csleep(1); if (game.dealer.handValue > 21) { printf("SYSTEM> %s busted!\n", game.dealer.name); break; } } // 勝敗判定 for (int i = 0; i < game.playerCount; i++) { processBet(&game, &game.players[i], bjRate); if (game.players[i].hasSplit) { processSplitBet(&game, &game.players[i], bjRate); } } displayStatus(&game); csleep(1); // プレイヤーのチップがなくなった場合はゲーム終了 for (int i = 0; i < game.playerCount; i++) { if (game.players[i].chips < minBets) { if (!game.players[i].isBot) { printf("SYSTEM> No chips for %s.\n", game.players[i].name); printf("Dealer> See you/~\n"); return 0; } else { printf("SYSTEM> No chips for %s.\n", game.players[i].name); printf("%s> %s\n", game.players[i].name, LEAVE_GREETINGS[rand() % 3]); csleep(1); initBot(&game.players[i], initChips); printf("%s> %s\n", game.players[i].name, ENTER_GREETINGS[rand() % 3]); } } else if (game.players[i].chips >= MAX_CHIPS) { if (!game.players[i].isBot) { printf("SYSTEM> %s has reached the maximum chips.\n", game.players[i].name); printf("Dealer> Now please leave.\n"); return 0; } else { printf("SYSTEM> %s has reached the maximum chips.\n", game.players[i].name); printf("%s> %s\n", game.players[i].name, LEAVE_GREETINGS[rand() % 3]); csleep(1); initBot(&game.players[i], initChips); printf("%s> %s\n", game.players[i].name, ENTER_GREETINGS[rand() % 3]); } } } // 次のゲームへ for (;;) { printf("Dealer> (N)ext game or (Q)uit?\nYou all> "); char buffer[BUFFER_SIZE]; if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) { continue; } if (buffer[0] == 'Q' || buffer[0] == 'q') { printf("Dealer> Bye bye/~\n"); return 0; } else if (buffer[0] == 'N' || buffer[0] == 'n') { break; } else { printf("SYSTEM> Invalid call.\n"); } } } return 0; }