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
.get_elapsed_time()
45 << std::setw(WIDE
+ 3) << nodes_count
46 << std::setw(WIDE
- 3) << " ";
47 const int ply
= tree
.get_ply();
49 if (current_position().turn_color() == 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
.get_ply();
67 if (current_position().turn_color() == WHITE
) {
68 stream
<< 1 + (ply
/ 2) << ". ";
70 stream
<< output_move(m
);
74 bool is_in_check
= is_check(current_position().turn_color());
76 // Find next move in TT
78 Transposition trans
= tt
.lookup(current_position().hash(), &is_empty
);
79 Move move
= trans
.best_move();
80 if (depth
> 0 && is_legal(move
) && trans
.bound() < 3) {
81 if (is_in_check
) stream
<< "+"; // Check
82 stream
<< output_pv(depth
- 1, trans
.value(), move
);
83 } else if (move
.is_null() && is_mate(score
)) {
84 if (is_in_check
) stream
<< "#"; // Mate
85 } else if (is_in_check
) {
86 stream
<< "+"; // Cut-off
93 std::string
Game::output_move(Move m
)
95 std::ostringstream stream
;
99 if (m
.castle_side() == QUEEN
) stream
<< "O-";
100 return stream
.str() + "O-O";
104 Square from
= m
.orig();
105 Piece p
= board
[from
];
106 PieceType t
= p
.type();
107 if (t
> PAWN
) stream
<< Piece(WHITE
, t
); // Upper case
112 Square to
= m
.dest();
113 for (int i
= 0; i
< pieces
.count(c
, t
); ++i
) {
114 Piece
other(c
, t
, i
);
115 if (other
== p
) continue;
116 Square s
= pieces
.position(other
);
117 if (board
.can_attack(t
, s
, to
) && board
.can_go(other
, s
, to
)) {
118 // If another piece of the same type can theoretically
119 // attack the destination (fast answer by array lookup)
120 // and can really go to this destination (not so fast
121 // answer) then a disambiguation is needed
122 stream
<< static_cast<char>('a' + m
.orig_file());
129 if (m
.is_capture()) {
130 if (t
== PAWN
) stream
<< static_cast<char>('a' + m
.orig_file());
135 stream
<< output_square(m
.dest_file(), m
.dest_rank());
138 if (m
.is_promotion()) {
139 stream
<< "=" << Piece(WHITE
, m
.promotion_type());
145 std::string
Game::output_square(File f
, Rank r
)
147 std::ostringstream stream
;
148 stream
<< static_cast<char>('a' + f
) << static_cast<char>('1' + r
);
152 std::string
get_stat(std::string title
, double value
, std::string unit
= "")
154 std::ostringstream stream
;
155 stream
<< std::left
<< " " << std::setw(20) << title
;
156 int precision
= (unit
== "%" ? 2 : 0);
157 stream
<< std::fixed
<< std::setprecision(precision
) << value
<< unit
;
161 std::string
get_meta(double value
, std::string unit
)
163 std::ostringstream stream
;
165 << std::fixed
<< std::setprecision(2) << value
<< unit
170 double get_percent(double a
, double b
)
176 std::string
print_table_stats(const HashTable
<T
>& table
, int table_size
)
180 for (int i
= 0; i
< table
.size(); ++i
) {
181 Hash h
= table
.hash_at(i
);
183 std::bitset
<64> b
= h
;
189 std::ostringstream stream
;
190 stream
<< get_stat("Table Size", table_size
/ 1024 / 1024, "Mb");
193 stream
<< get_stat("Entries", table
.size());
196 stream
<< get_stat("Usage", table
.usage());
197 stream
<< get_meta(get_percent(table
.usage(), table
.size()), "%");
200 stream
<< get_stat("0's", get_percent(zeros
, 64 * table
.usage()), "%");
203 stream
<< get_stat("1's", get_percent(ones
, 64 * table
.usage()), "%");
206 stream
<< get_stat("Lookups", table
.nb_lookups());
209 stream
<< get_stat("Hits", table
.nb_hits());
210 stream
<< get_meta(get_percent(table
.nb_hits(),
211 table
.nb_lookups()), "%");
214 stream
<< get_stat("Collisions", table
.nb_collisions());
215 stream
<< get_meta(get_percent(table
.nb_collisions(),
216 table
.nb_lookups()), "%");
219 stream
<< get_stat("Misses", table
.nb_misses());
220 stream
<< get_meta(get_percent(table
.nb_misses(),
221 table
.nb_lookups()), "%");
227 void Game::print_tt_stats()
229 std::cout
<< "Transposition Table usage:" << std::endl
;
230 std::cout
<< print_table_stats(tt
, TT_SIZE
) << std::endl
;
232 std::cout
<< "Material Table usage:" << std::endl
;
233 std::cout
<< print_table_stats(material_table
, MT_SIZE
) << std::endl
;
236 std::string
Game::debug_move(Move m
)
238 std::ostringstream stream
;
239 Color c
= current_position().turn_color();
240 stream
<< std::endl
<< board
<< std::endl
241 << (c
== WHITE
? "White" : "Black") << " to move" << std::endl
242 << "m = " << output_move(m
) << " (" << m
<< ")" << std::endl
243 << "m is en passant: " << m
.is_en_passant() << std::endl
244 << "m is promotion: " << m
.is_promotion() << std::endl
245 << "m is legal: " << is_legal(m
) << std::endl
246 << std::hex
<< current_position().hash();