minimax with alpha-beta pruning
このコミットが含まれているのは:
コミット
cb4587847d
137
uttt.c
137
uttt.c
|
@ -39,14 +39,16 @@ struct ut_game
|
||||||
};
|
};
|
||||||
|
|
||||||
const char HELP_TEXT[] = "\
|
const char HELP_TEXT[] = "\
|
||||||
Usage: uttt (--local | --host | --join)\n\
|
Usage: uttt (--local | --agent | --host | --join)\n\
|
||||||
\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\
|
--host host game at 127.0.0.1:6669\n\
|
||||||
--join join 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_local[] = "--local";
|
||||||
|
const char arg_agent[] = "--agent";
|
||||||
const char arg_host[] = "--host";
|
const char arg_host[] = "--host";
|
||||||
const char arg_join[] = "--join";
|
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);
|
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)
|
void finish(int sig)
|
||||||
{
|
{
|
||||||
// putchar('\n');
|
// putchar('\n');
|
||||||
|
@ -718,6 +760,9 @@ int main(int argc, char **argv) {
|
||||||
} else if (strncmp(argv[1], arg_local, sizeof(arg_local)) == 0) {
|
} else if (strncmp(argv[1], arg_local, sizeof(arg_local)) == 0) {
|
||||||
begin();
|
begin();
|
||||||
waitfinish(ut_local_game(&state, &game));
|
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) {
|
} else if (strncmp(argv[1], arg_host, sizeof(arg_host)) == 0) {
|
||||||
begin();
|
begin();
|
||||||
waitfinish(ut_host_game(&state, &game));
|
waitfinish(ut_host_game(&state, &game));
|
||||||
|
@ -730,3 +775,91 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
|
読み込み中…
新しいイシューから参照