minimax with alpha-beta pruning

このコミットが含まれているのは:
woosh 2023-11-16 05:07:16 +00:00
コミット cb4587847d
1個のファイルの変更135行の追加2行の削除

137
uttt.c
ファイルの表示

@ -39,14 +39,16 @@ struct ut_game
};
const char HELP_TEXT[] = "\
Usage: uttt (--local | --host | --join)\n\
Usage: uttt (--local | --agent | --host | --join)\n\
\n\
--local play non-network game\n\
--local play local game\n\
--agent play against AI agent\n\
--host host game at 127.0.0.1:6669\n\
--join join game at 127.0.0.1:6669\n\
";
const char arg_local[] = "--local";
const char arg_agent[] = "--agent";
const char arg_host[] = "--host";
const char arg_join[] = "--join";
@ -676,6 +678,46 @@ int ut_join_game(struct ut_state *state, struct ut_game *game) {
return ut_network_game(state, game, sock, *player, false);
}
int ut_agentgetmove(const struct ut_state *state, const struct ut_game *game, struct ut_move *move);
int ut_agent_game(struct ut_state *state, struct ut_game *game) {
char player;
if ((player = ut_random_player()) < 0) {return 1;}
for(;;)
{
struct ut_move m = {4, 4};
ut_curserase();
ut_cursdraw(state, game);
char w = ut_winner(state);
if(w)
{
if(w == ' ')
{
ut_cursprintf("Draw!\n");
}
else
{
ut_cursprintf("%c wins!\n", (int)w);
}
break;
}
if (state->player == player) {
if(ut_cursgetmove(state, &m)) {continue;}
} else {
ut_cursprintf("Waiting for AI agent ...\n");
refresh();
if(ut_agentgetmove(state, game, &m))
{
ut_cursprintf("Agent failed - exiting\n");
return 1;
}
}
if(ut_move(state, state, m)) {continue;}
game->moves[game->l++] = m;
}
return 0;
}
void finish(int sig)
{
// putchar('\n');
@ -718,6 +760,9 @@ int main(int argc, char **argv) {
} else if (strncmp(argv[1], arg_local, sizeof(arg_local)) == 0) {
begin();
waitfinish(ut_local_game(&state, &game));
} else if (strncmp(argv[1], arg_agent, sizeof(arg_agent)) == 0) {
begin();
waitfinish(ut_agent_game(&state, &game));
} else if (strncmp(argv[1], arg_host, sizeof(arg_host)) == 0) {
begin();
waitfinish(ut_host_game(&state, &game));
@ -730,3 +775,91 @@ int main(int argc, char **argv) {
}
return 0;
}
int ut_boardValue(const char *tiles, int offset, int stride)
{
int v = 0;
for(int r = 0; r < 3; r++)
for(int c = 0; c < 3; c++)
v += (T(r, c) == 'X') ? 1 : (T(r, c) == 'O') ? -1 : 0;
return v;
}
#define UT_VALUEMAX 81
#define UT_VALUEMIN (-81)
int ut_value(const struct ut_state *state)
{
int v = 0;
char winner = ut_winner(state);
if(winner != '\0')
{
return (winner == 'X') ? 81 : (winner == 'O') ? -81 : 0;
}
for(int r = 0; r < 3; r++)
for(int c = 0; c < 3; c++)
v += (state->boards[r][c] == '\0') ? ut_boardValue((char *)state->tiles, 27 * r + 3 * c, 9) :
(state->boards[r][c] == 'X') ? 9 : (state->boards[r][c] == 'O') ? -9 : 0;
return v;
}
int ut_alphabetaq(const struct ut_state *state, struct ut_move move, int depth, int a, int b)
{
struct ut_state next;
if(ut_move(&next, state, move)) {return (state->player == 'X') ? UT_VALUEMIN - 1 : UT_VALUEMAX + 1;}
int q = ut_value(&next);
if(depth <= 0 || q <= UT_VALUEMIN || q >= UT_VALUEMAX) {return q;}
if(next.player == 'X')
{
q = UT_VALUEMIN - 1;
for(int r = 0; r < 9; r++)
for(int c = 0; c < 9; c++)
{
struct ut_move next_move = (struct ut_move){r, c};
int next_q = ut_alphabetaq(&next, next_move, depth - 1, a, b);
if(next_q > q) {q = next_q;}
if(q > b) {return q;}
a = q > a ? q : a;
}
}
else
{
q = UT_VALUEMAX + 1;
for(int r = 0; r < 9; r++)
for(int c = 0; c < 9; c++)
{
struct ut_move next_move = (struct ut_move){r, c};
int next_q = ut_alphabetaq(&next, next_move, depth - 1, a, b);
if(next_q < q) {q = next_q;}
if(q < a) {return q;}
b = q < b ? q : b;
}
}
return q;
}
#define UT_DEPTH 5
struct ut_move ut_minimax(const struct ut_state *state)
{
struct ut_move best_move = {-1, -1};
int best_q = (state->player == 'X') ? UT_VALUEMIN - 1 : UT_VALUEMAX + 1;
for(int r = 0; r < 9; r++)
for(int c = 0; c < 9; c++)
{
struct ut_move move = (struct ut_move){r, c};
int q = ut_alphabetaq(state, move, UT_DEPTH, UT_VALUEMIN - 1, UT_VALUEMAX + 1);
if((state->player == 'X') ? q > best_q : q < best_q)
{
best_q = q;
best_move = move;
}
}
return best_move;
}
int ut_agentgetmove(const struct ut_state *state, const struct ut_game *game, struct ut_move *move)
{
*move = ut_minimax(state);
return (move->r < 0 || move->r >= 9 || move->c < 0 || move->c >= 9);
}