Last active
September 17, 2021 06:48
-
-
Save shiracamus/b7953c7ed544e6c450c90bb25f51d1df to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <time.h> | |
#include <sys/time.h> | |
typedef enum { NONE, BLACK, WHITE, INVALID } stone_t; | |
const char *STONE[] = {" ", "○", "●", "??"}; | |
#define SIZE 8 | |
stone_t board[SIZE][SIZE]; | |
const char ROW[] = "12345678"; | |
const char COL[] = "abcdefgh"; | |
typedef struct { | |
char *name; | |
stone_t stone; | |
void (*play)(stone_t stone); | |
} player_t; | |
void init_random() { | |
struct timeval now; | |
gettimeofday(&now, NULL); | |
srand((unsigned int)now.tv_usec); | |
} | |
void init_board() { | |
for (int y = 0; y < SIZE; y++) { | |
for (int x = 0; x < SIZE; x++) { | |
board[y][x] = NONE; | |
} | |
} | |
board[SIZE / 2 - 1][SIZE / 2 - 1] = WHITE; | |
board[SIZE / 2 - 1][SIZE / 2 + 0] = BLACK; | |
board[SIZE / 2 + 0][SIZE / 2 - 1] = BLACK; | |
board[SIZE / 2 + 0][SIZE / 2 + 0] = WHITE; | |
} | |
void show_board() { | |
printf("\n "); | |
for (int x = 0; x < SIZE; x++) { | |
printf(" %c ", COL[x]); | |
} | |
printf("\n -------------------------\n"); | |
for (int y = 0; y < SIZE; y++) { | |
printf("%c", ROW[y]); | |
for (int x = 0; x < SIZE; x++) { | |
printf("|%s", STONE[board[y][x]]); | |
} | |
printf("|\n -------------------------\n"); | |
} | |
} | |
bool valid(int y, int x) { | |
return 0 <= y && y < SIZE && 0 <= x && x < SIZE; | |
} | |
stone_t stone_at(int y, int x) { | |
return valid(y, x) ? board[y][x] : INVALID; | |
} | |
bool reversible_line(stone_t stone, int y, int x, int dy, int dx) { | |
stone_t reverse = stone == BLACK ? WHITE : BLACK; | |
if (stone_at(y + dy, x + dx) != reverse) return false; | |
do { | |
y += dy; | |
x += dx; | |
} while (stone_at(y, x) == reverse); | |
return stone_at(y, x) == stone; | |
} | |
bool reversible(stone_t stone, int y, int x) { | |
if (stone_at(y, x) != NONE) return false; | |
for (int dy = -1; dy <= 1; dy++) { | |
for (int dx = -1; dx <= 1; dx++) { | |
if (dy == 0 && dx == 0) continue; | |
if (reversible_line(stone, y, x, dy, dx)) return true; | |
} | |
} | |
return false; | |
} | |
bool putable(stone_t stone) { | |
for (int y = 0; y < SIZE; y++) { | |
for (int x = 0; x < SIZE; x++) { | |
if (reversible(stone, y, x)) return true; | |
} | |
} | |
return false; | |
} | |
int count(stone_t stone) { | |
int counter = 0; | |
for (int y = 0; y < SIZE; y++) { | |
for (int x = 0; x < SIZE; x++) { | |
if (board[y][x] == stone) { | |
counter++; | |
} | |
} | |
} | |
return counter; | |
} | |
bool playable() { | |
return count(NONE) > 0 && (putable(BLACK) || putable(WHITE)); | |
} | |
void reverse_line(stone_t stone, int y, int x, int dy, int dx) { | |
if (!reversible_line(stone, y, x, dy, dx)) return; | |
while (stone_at(y + dy, x + dx) != stone) { | |
y += dy; | |
x += dx; | |
board[y][x] = stone; | |
} | |
} | |
void reverse(stone_t stone, int y, int x) { | |
for (int dy = -1; dy <= 1; dy++) { | |
for (int dx = -1; dx <= 1; dx++) { | |
if (dy == 0 && dx == 0) continue; | |
reverse_line(stone, y, x, dy, dx); | |
} | |
} | |
} | |
bool put(stone_t stone, int y, int x) { | |
if (!reversible(stone, y, x)) return false; | |
board[y][x] = stone; | |
reverse(stone, y, x); | |
return true; | |
} | |
int ask_position(const char *prompt, const char *selection) { | |
while (true) { | |
printf("%s", prompt); | |
char c; | |
if (scanf("%c", &c) == 1) { | |
char *selected = strchr(selection, c); | |
if (selected != NULL) return selected - selection; | |
} else { | |
if (feof(stdin) || ferror(stdin)) exit(1); | |
scanf("%*[^\n]"); // 不要な入力を読み捨てる | |
} | |
printf("%s の中から指定してください\n", selection); | |
} | |
} | |
void play_human(stone_t stone) { | |
while (true) { | |
int y = ask_position("行(1-8): ", ROW); | |
int x = ask_position("桁(a-h): ", COL); | |
if (put(stone, y, x)) return; | |
printf("そこには置けません\n"); | |
} | |
} | |
void play_random(stone_t stone) { | |
while (true) { | |
int y = rand() % SIZE; | |
int x = rand() % SIZE; | |
if (put(stone, y, x)) { | |
printf("行: %c\n列: %c\n", ROW[y], COL[x]); | |
return; | |
} | |
} | |
} | |
int evaluate(stone_t stone, int y, int x) { | |
stone_t backup[SIZE][SIZE]; | |
memcpy(backup, board, sizeof(backup)); | |
int score = put(stone, y, x) ? count(stone) : -1; | |
memcpy(board, backup, sizeof(backup)); | |
return score; | |
} | |
void play_eval_1step(stone_t stone) { | |
int best_score = -1, best_x, best_y; | |
for (int y = 0; y < SIZE; y++) { | |
for (int x = 0; x < SIZE; x++) { | |
int score = evaluate(stone, y, x); | |
if (score > best_score) { | |
best_score = score; | |
best_y = y; | |
best_x = x; | |
} | |
} | |
} | |
printf("行: %c\n列: %c\n", ROW[best_y], COL[best_x]); | |
put(stone, best_y, best_x); | |
} | |
void play(player_t *player1, player_t *player2) { | |
player_t *player = player1; | |
while (playable()) { | |
printf("\n%s(%s)の番です\n", player->name, STONE[player->stone]); | |
if (putable(player->stone)) { | |
player->play(player->stone); | |
show_board(); | |
} else { | |
printf("置ける場所がありません。パスします。\n"); | |
} | |
player = player == player1 ? player2 : player1; | |
} | |
} | |
void show_judgement() { | |
int black = count(BLACK); | |
int white = count(WHITE); | |
printf("黒の数: %2d\n白の数: %2d\n", black, white); | |
if (black > white) { | |
printf("黒の勝ちです\n"); | |
} else if (black < white) { | |
printf("白の勝ちです\n"); | |
} else { | |
printf("引き分けです\n"); | |
} | |
} | |
int main() { | |
//player_t player1 = {"黒", BLACK, play_human}; | |
player_t player1 = {"黒", BLACK, play_random}; | |
player_t player2 = {"白", WHITE, play_eval_1step}; | |
init_random(); | |
init_board(); | |
show_board(); | |
long start = time(NULL); | |
play(&player1, &player2); | |
printf("\n試合時間: %ld秒\n", time(NULL) - start); | |
show_judgement(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment