1 /* Copyright (C) 2007-2011 Vincent Ollivier
3 * Purple Haze is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * Purple Haze is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 static const int WIDE
= 10;
28 void Game::print_thinking_header()
30 if (!output_thinking
) {
33 std::cout
<< std::setw(4) << "ply"
34 << std::setw(WIDE
- 1) << "score"
35 << std::setw(WIDE
) << "time"
36 << std::setw(WIDE
+ 3) << "nodes"
37 << std::setw(WIDE
) << "pv"
41 void Game::print_thinking(int depth
, int score
, Move m
)
43 if (!output_thinking
) {
46 std::cout
<< std::setw(4) << depth
47 << std::setw(WIDE
- 1) << score
48 << std::setw(WIDE
) << time
.elapsed()
49 << std::setw(WIDE
+ 3) << nodes_count
50 << std::setw(WIDE
- 3) << " ";
51 const int ply
= tree
.ply();
53 if (current_position().side() == BLACK
) {
54 std::cout
<< " " << 1 + (ply
/ 2) << ". ...";
57 assert(is_legal(m
) || assert_msg(debug_move(m
)));
58 std::cout
<< output_pv(depth
, score
, m
) << std::endl
;
61 static bool is_mate(int score
)
63 return ((score
< -INF
+ MAX_PLY
) || (INF
- MAX_PLY
< score
));
66 std::string
Game::output_pv(int depth
, int score
, Move m
)
68 std::ostringstream stream
;
70 const int ply
= tree
.ply();
71 if (current_position().side() == WHITE
) {
72 stream
<< 1 + (ply
/ 2) << ". ";
74 stream
<< output_move(m
);
76 make_move(m
); // Update nodes_count
79 bool is_in_check
= is_check(current_position().side());
81 // Find next move in TT
83 Transposition trans
= tt
.lookup(current_position().hash(), &is_empty
);
84 Move move
= trans
.best_move();
85 if (depth
> 0 && is_legal(move
) && trans
.bound() < 3) {
87 stream
<< "+"; // Check
89 stream
<< output_pv(depth
- 1, trans
.value(), move
);
90 } else if (move
.is_null() && is_mate(score
)) {
92 stream
<< "#"; // Mate
94 } else if (is_in_check
) {
95 stream
<< "+"; // Cut-off
102 std::string
Game::output_move(Move m
)
104 std::ostringstream stream
;
108 if (m
.castle_side() == QUEEN
) {
111 return stream
.str() + "O-O";
115 Square from
= m
.orig();
116 Piece p
= board
[from
];
117 PieceType t
= p
.type();
119 stream
<< Piece(WHITE
, t
); // Upper case
125 Square to
= m
.dest();
126 for (int i
= 0; i
< pieces
.count(c
, t
); ++i
) {
127 Piece
other(c
, t
, i
);
131 Square s
= pieces
.position(other
);
132 if (board
.can_attack(t
, s
, to
) && board
.can_go(other
, s
, to
)) {
133 // If another piece of the same type can theoretically
134 // attack the destination (fast answer by array lookup)
135 // and can really go to this destination (not so fast
136 // answer) then a disambiguation is needed
137 stream
<< static_cast<char>('a' + m
.orig_file());
144 if (m
.is_capture()) {
146 stream
<< static_cast<char>('a' + m
.orig_file());
152 stream
<< output_square(m
.dest_file(), m
.dest_rank());
155 if (m
.is_promotion()) {
156 stream
<< "=" << Piece(WHITE
, m
.promotion_type());
162 std::string
Game::output_square(File f
, Rank r
)
164 std::ostringstream stream
;
165 stream
<< static_cast<char>('a' + f
) << static_cast<char>('1' + r
);
169 std::string
get_stat(std::string title
, double value
, std::string unit
= "")
171 std::ostringstream stream
;
172 stream
<< std::left
<< " " << std::setw(20) << title
;
173 int precision
= (unit
== "%" ? 2 : 0);
174 stream
<< std::fixed
<< std::setprecision(precision
) << value
<< unit
;
178 std::string
get_meta(double value
, std::string unit
)
180 std::ostringstream stream
;
182 << std::fixed
<< std::setprecision(2) << value
<< unit
187 static double get_percent(double a
, double b
)
193 std::string
print_table_stats(const HashTable
<T
>& table
, int table_size
)
197 for (int i
= 0; i
< table
.size(); ++i
) {
198 Hash h
= table
.hash_at(i
);
202 std::bitset
<64> b
= h
;
208 std::ostringstream stream
;
209 stream
<< get_stat("Table Size", table_size
/ 1024 / 1024, "Mb");
212 stream
<< get_stat("Entries", table
.size());
215 stream
<< get_stat("Usage", table
.usage());
216 stream
<< get_meta(get_percent(table
.usage(), table
.size()), "%");
219 stream
<< get_stat("0's", get_percent(zeros
, 64 * table
.usage()), "%");
222 stream
<< get_stat("1's", get_percent(ones
, 64 * table
.usage()), "%");
225 stream
<< get_stat("Lookups", table
.nb_lookups());
228 stream
<< get_stat("Hits", table
.nb_hits());
229 stream
<< get_meta(get_percent(table
.nb_hits(),
230 table
.nb_lookups()), "%");
233 stream
<< get_stat("Collisions", table
.nb_collisions());
234 stream
<< get_meta(get_percent(table
.nb_collisions(),
235 table
.nb_lookups()), "%");
238 stream
<< get_stat("Misses", table
.nb_misses());
239 stream
<< get_meta(get_percent(table
.nb_misses(),
240 table
.nb_lookups()), "%");
246 void Game::print_tt_stats()
248 std::cout
<< "Transposition Table usage:" << std::endl
;
249 std::cout
<< print_table_stats(tt
, TT_SIZE
) << std::endl
;
251 std::cout
<< "Material Table usage:" << std::endl
;
252 std::cout
<< print_table_stats(material_table
, MT_SIZE
) << std::endl
;
255 std::string
Game::debug_move(Move m
)
257 std::ostringstream stream
;
258 Color c
= current_position().side();
259 stream
<< std::endl
<< board
<< std::endl
260 << (c
== WHITE
? "White" : "Black") << " to move" << std::endl
261 << "m = " << output_move(m
) << " (" << m
<< ")" << std::endl
262 << "m is en passant: " << m
.is_en_passant() << std::endl
263 << "m is promotion: " << m
.is_promotion() << std::endl
264 << "m is legal: " << is_legal(m
) << std::endl
265 << std::hex
<< current_position().hash();