Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Last active September 17, 2021 06:48
Show Gist options
  • Save shiracamus/b7953c7ed544e6c450c90bb25f51d1df to your computer and use it in GitHub Desktop.
Save shiracamus/b7953c7ed544e6c450c90bb25f51d1df to your computer and use it in GitHub Desktop.
#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