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
) return;
31 std::cout
<< std::setw(4) << "ply"
32 << std::setw(WIDE
- 1) << "score"
33 << std::setw(WIDE
) << "time"
34 << std::setw(WIDE
+ 3) << "nodes"
35 << std::setw(WIDE
) << "pv"
39 void Game::print_thinking(int depth
, int score
, Move m
)
41 if (!output_thinking
) return;
42 std::cout
<< std::setw(4) << depth
43 << std::setw(WIDE
- 1) << score
44 << std::setw(WIDE
) << time
.elapsed()
45 << std::setw(WIDE
+ 3) << nodes_count
46 << std::setw(WIDE
- 3) << " ";
47 const int ply
= tree
.ply();
49 if (current_position().side() == BLACK
) {
50 std::cout
<< " " << 1 + (ply
/ 2) << ". ...";
53 assert(is_legal(m
) || assert_msg(debug_move(m
)));
54 std::cout
<< output_pv(depth
, score
, m
) << std::endl
;
57 bool is_mate(int score
)
59 return ((score
< -INF
+ MAX_PLY
) || (INF
- MAX_PLY
< score
));
62 std::string
Game::output_pv(int depth
, int score
, Move m
)
64 std::ostringstream stream
;
66 const int ply
= tree
.ply();
67 if (current_position().side() == WHITE
) {
68 stream
<< 1 + (ply
/ 2) << ". ";
70 stream
<< output_move(m
);
72 make_move(m
); // Update nodes_count
75 bool is_in_check
= is_check(current_position().side());
77 // Find next move in TT
79 Transposition trans
= tt
.lookup(current_position().hash(), &is_empty
);
80 Move move
= trans
.best_move();
81 if (depth
> 0 && is_legal(move
) && trans
.bound() < 3) {
82 if (is_in_check
) stream
<< "+"; // Check
83 stream
<< output_pv(depth
- 1, trans
.value(), move
);
84 } else if (move
.is_null() && is_mate(score
)) {
85 if (is_in_check
) stream
<< "#"; // Mate
86 } else if (is_in_check
) {
87 stream
<< "+"; // Cut-off
94 std::string
Game::output_move(Move m
)
96 std::ostringstream stream
;
100 if (m
.castle_side() == QUEEN
) stream
<< "O-";
101 return stream
.str() + "O-O";
105 Square from
= m
.orig();
106 Piece p
= board
[from
];
107 PieceType t
= p
.type();
108 if (t
> PAWN
) stream
<< Piece(WHITE
, t
); // Upper case
113 Square to
= m
.dest();
114 for (int i
= 0; i
< pieces
.count(c
, t
); ++i
) {
115 Piece
other(c
, t
, i
);
116 if (other
== p
) continue;
117 Square s
= pieces
.position(other
);
118 if (board
.can_attack(t
, s
, to
) && board
.can_go(other
, s
, to
)) {
119 // If another piece of the same type can theoretically
120 // attack the destination (fast answer by array lookup)
121 // and can really go to this destination (not so fast
122 // answer) then a disambiguation is needed
123 stream
<< static_cast<char>('a' + m
.orig_file());
130 if (m
.is_capture()) {
131 if (t
== PAWN
) stream
<< static_cast<char>('a' + m
.orig_file());
136 stream
<< output_square(m
.dest_file(), m
.dest_rank());
139 if (m
.is_promotion()) {
140 stream
<< "=" << Piece(WHITE
, m
.promotion_type());
146 std::string
Game::output_square(File f
, Rank r
)
148 std::ostringstream stream
;
149 stream
<< static_cast<char>('a' + f
) << static_cast<char>('1' + r
);
153 std::string
get_stat(std::string title
, double value
, std::string unit
= "")
155 std::ostringstream stream
;
156 stream
<< std::left
<< " " << std::setw(20) << title
;
157 int precision
= (unit
== "%" ? 2 : 0);
158 stream
<< std::fixed
<< std::setprecision(precision
) << value
<< unit
;
162 std::string
get_meta(double value
, std::string unit
)
164 std::ostringstream stream
;
166 << std::fixed
<< std::setprecision(2) << value
<< unit
171 double get_percent(double a
, double b
)
177 std::string
print_table_stats(const HashTable
<T
>& table
, int table_size
)
181 for (int i
= 0; i
< table
.size(); ++i
) {
182 Hash h
= table
.hash_at(i
);
184 std::bitset
<64> b
= h
;
190 std::ostringstream stream
;
191 stream
<< get_stat("Table Size", table_size
/ 1024 / 1024, "Mb");
194 stream
<< get_stat("Entries", table
.size());
197 stream
<< get_stat("Usage", table
.usage());
198 stream
<< get_meta(get_percent(table
.usage(), table
.size()), "%");
201 stream
<< get_stat("0's", get_percent(zeros
, 64 * table
.usage()), "%");
204 stream
<< get_stat("1's", get_percent(ones
, 64 * table
.usage()), "%");
207 stream
<< get_stat("Lookups", table
.nb_lookups());
210 stream
<< get_stat("Hits", table
.nb_hits());
211 stream
<< get_meta(get_percent(table
.nb_hits(),
212 table
.nb_lookups()), "%");
215 stream
<< get_stat("Collisions", table
.nb_collisions());
216 stream
<< get_meta(get_percent(table
.nb_collisions(),
217 table
.nb_lookups()), "%");
220 stream
<< get_stat("Misses", table
.nb_misses());
221 stream
<< get_meta(get_percent(table
.nb_misses(),
222 table
.nb_lookups()), "%");
228 void Game::print_tt_stats()
230 std::cout
<< "Transposition Table usage:" << std::endl
;
231 std::cout
<< print_table_stats(tt
, TT_SIZE
) << std::endl
;
233 std::cout
<< "Material Table usage:" << std::endl
;
234 std::cout
<< print_table_stats(material_table
, MT_SIZE
) << std::endl
;
237 std::string
Game::debug_move(Move m
)
239 std::ostringstream stream
;
240 Color c
= current_position().side();
241 stream
<< std::endl
<< board
<< std::endl
242 << (c
== WHITE
? "White" : "Black") << " to move" << std::endl
243 << "m = " << output_move(m
) << " (" << m
<< ")" << std::endl
244 << "m is en passant: " << m
.is_en_passant() << std::endl
245 << "m is promotion: " << m
.is_promotion() << std::endl
246 << "m is legal: " << is_legal(m
) << std::endl
247 << std::hex
<< current_position().hash();