Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
negamax_simple_example.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
48# include <iostream>
49
50# include <State_Search.H>
51# include <tpl_array.H>
52
53using Aleph::Array;
54
55namespace
56{
57
58namespace Search = Aleph::Search;
59
60// --- State -----------------------------------------------------------------
61
62struct TicTacToeState
63{
64 Array<int> board; // 0 = empty, +1 = X, -1 = O
65 int player = 1; // side to move (+1 or -1)
66 size_t moves_played = 0;
67
68 TicTacToeState() : board(size_t(9), 0) {}
69};
70
71// --- Domain ----------------------------------------------------------------
72
73class TicTacToeDomain
74{
75public:
76 struct Move
77 {
78 size_t cell = 0;
79 bool operator==(const Move &) const noexcept = default;
80 };
81
82 using State = TicTacToeState;
83 using Score = int;
84
85 bool is_terminal(const State &state) const
86 {
87 return winner(state) != 0 or state.moves_played == 9;
88 }
89
91 Score evaluate(const State &state) const
92 {
93 const int w = winner(state);
94 if (w != 0)
95 return w == state.player ? 100 : -100;
96 return 0; // draw
97 }
98
99 void apply(State &state, const Move &move) const
100 {
101 state.board[move.cell] = state.player;
102 state.player = -state.player;
103 ++state.moves_played;
104 }
105
106 void undo(State &state, const Move &move) const
107 {
108 --state.moves_played;
109 state.player = -state.player;
110 state.board[move.cell] = 0;
111 }
112
113 template <typename Visitor>
114 bool for_each_successor(const State &state, Visitor visit) const
115 {
116 for (size_t i = 0; i < 9; ++i)
117 if (state.board[i] == 0 and not visit(Move{i}))
118 return false;
119 return true;
120 }
121
122private:
123 [[nodiscard]] static int winner(const State &state) noexcept
124 {
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},
128 {0, 4, 8}, {2, 4, 6}
129 };
130 for (const auto &line : lines)
131 {
132 const int a = state.board[line[0]];
133 if (a != 0 and a == state.board[line[1]] and a == state.board[line[2]])
134 return a;
135 }
136 return 0;
137 }
138};
139
140// --- Display ---------------------------------------------------------------
141
142void print_board(const TicTacToeState &state)
143{
144 for (size_t row = 0; row < 3; ++row)
145 {
146 for (size_t col = 0; col < 3; ++col)
147 {
148 const int cell = state.board[row * 3 + col];
149 std::cout << (cell == 1 ? 'X' : cell == -1 ? 'O' : '.');
150 }
151 std::cout << '\n';
152 }
153}
154
155} // end anonymous namespace
156
157int main()
158{
159 TicTacToeDomain domain;
160 TicTacToeState root;
161
162 // Run plain Negamax to full depth (no limits needed for a 9-ply game).
163 auto result = Search::negamax_search(domain, root);
164
165 std::cout << "Tic-Tac-Toe — simple Negamax example\n\n";
166
168 std::cout << '\n';
169
170 std::cout << "Game-theoretic value: " << result.value
171 << " (0 = draw)\n";
172 if (result.has_principal_variation())
173 std::cout << "Best opening move: cell " << result.first_move().cell << '\n';
174 else
175 std::cout << "Best opening move: no principal variation\n";
176 std::cout << "Visited states: " << result.stats.visited_states
177 << '\n';
178 std::cout << "Heuristic evals: " << result.stats.heuristic_evaluations
179 << '\n';
180
181 // Replay the principal variation.
182 std::cout << "\nPrincipal variation (" << result.principal_variation.size()
183 << " moves):\n";
184 TicTacToeState replay = root;
185 for (size_t i = 0; i < result.principal_variation.size(); ++i)
186 {
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';
191 }
192
193 std::cout << "\nFinal board:\n";
195
196 return 0;
197}
Umbrella header for the implicit state-space search framework.
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
__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)
Definition gmpfrxx.h:4060
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.