66 size_t moves_played = 0;
68 TicTacToeState() : board(size_t(9), 0) {}
79 bool operator==(
const Move &)
const noexcept =
default;
82 using State = TicTacToeState;
87 return winner(state) != 0
or state.moves_played == 9;
91 Score
evaluate(
const State &state)
const
95 return w == state.player ? 100 : -100;
99 void apply(State &state,
const Move &move)
const
101 state.board[move.cell] = state.player;
102 state.player = -state.player;
103 ++state.moves_played;
106 void undo(State &state,
const Move &move)
const
108 --state.moves_played;
109 state.player = -state.player;
110 state.board[move.cell] = 0;
113 template <
typename Visitor>
114 bool for_each_successor(
const State &state,
Visitor visit)
const
116 for (
size_t i = 0; i < 9; ++i)
125 static constexpr size_t lines[8][3] = {
126 {0, 1, 2}, {3, 4, 5}, {6, 7, 8},
127 {0, 3, 6}, {1, 4, 7}, {2, 5, 8},
130 for (
const auto &line :
lines)
132 const int a = state.board[line[0]];
133 if (a != 0
and a == state.board[line[1]]
and a == state.board[line[2]])
144 for (
size_t row = 0; row < 3; ++row)
146 for (
size_t col = 0; col < 3; ++col)
148 const int cell = state.board[row * 3 + col];
149 std::cout << (cell == 1 ?
'X' : cell == -1 ?
'O' :
'.');
159 TicTacToeDomain domain;
163 auto result = Search::negamax_search(domain,
root);
165 std::cout <<
"Tic-Tac-Toe — simple Negamax example\n\n";
170 std::cout <<
"Game-theoretic value: " << result.value
172 if (result.has_principal_variation())
173 std::cout <<
"Best opening move: cell " << result.first_move().cell <<
'\n';
175 std::cout <<
"Best opening move: no principal variation\n";
176 std::cout <<
"Visited states: " << result.stats.visited_states
178 std::cout <<
"Heuristic evals: " << result.stats.heuristic_evaluations
182 std::cout <<
"\nPrincipal variation (" << result.principal_variation.size()
185 for (
size_t i = 0; i < result.principal_variation.size(); ++i)
187 const auto &move = result.principal_variation[i];
188 domain.apply(
replay, move);
189 std::cout <<
" Move " << i + 1 <<
": cell " << move.cell
190 <<
" by " << (
replay.player == -1 ?
'X' :
'O') <<
'\n';
193 std::cout <<
"\nFinal board:\n";
Umbrella header for the implicit state-space search framework.
Simple dynamic array with automatic resizing and functional operations.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
User-facing facade exported by the umbrella search header.
and
Check uniqueness with explicit hash + equality functors.
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Dynamic array container with automatic resizing.