Remove unused part of Search code
[purplehaze.git] / src / output.cpp
blob5a5cac383ac3ce9b944cd00fe7b657d98de0977a
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/>.
17 #include <bitset>
18 #include <cassert>
19 #include <iostream>
20 #include <iomanip>
21 #include <string>
22 #include <sstream>
24 #include "game.h"
26 static const int WIDE = 10;
28 void Game::print_thinking_header()
30 if (!output_thinking) {
31 return;
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"
38 << std::endl;
41 void Game::print_thinking(int depth, int score, Move m)
43 if (!output_thinking) {
44 return;
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;
69 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
77 --nodes_count;
79 bool is_in_check = is_check(current_position().side());
81 // Find next move in TT
82 bool is_empty;
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) {
86 if (is_in_check) {
87 stream << "+"; // Check
89 stream << output_pv(depth - 1, trans.value(), move);
90 } else if (move.is_null() && is_mate(score)) {
91 if (is_in_check) {
92 stream << "#"; // Mate
94 } else if (is_in_check) {
95 stream << "+"; // Cut-off
98 undo_move(m);
99 return stream.str();
102 std::string Game::output_move(Move m)
104 std::ostringstream stream;
106 // Castling
107 if (m.is_castle()) {
108 if (m.castle_side() == QUEEN) {
109 stream << "O-";
111 return stream.str() + "O-O";
114 // Type of piece
115 Square from = m.orig();
116 Piece p = board[from];
117 PieceType t = p.type();
118 if (t > PAWN) {
119 stream << Piece(WHITE, t); // Upper case
122 // Disambiguation
123 if (t != PAWN) {
124 Color c = p.color();
125 Square to = m.dest();
126 for (int i = 0; i < pieces.count(c, t); ++i) {
127 Piece other(c, t, i);
128 if (other == p) {
129 continue;
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());
138 break;
143 // Capture
144 if (m.is_capture()) {
145 if (t == PAWN) {
146 stream << static_cast<char>('a' + m.orig_file());
148 stream << "x";
151 // Destination
152 stream << output_square(m.dest_file(), m.dest_rank());
154 // Promotion
155 if (m.is_promotion()) {
156 stream << "=" << Piece(WHITE, m.promotion_type());
159 return stream.str();
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);
166 return stream.str();
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;
175 return stream.str();
178 std::string get_meta(double value, std::string unit)
180 std::ostringstream stream;
181 stream << " ("
182 << std::fixed << std::setprecision(2) << value << unit
183 << ")";
184 return stream.str();
187 static double get_percent(double a, double b)
189 return 100 * a / b;
192 template <class T>
193 std::string print_table_stats(const HashTable<T>& table, int table_size)
195 long zeros = 0;
196 long ones = 0;
197 for (int i = 0; i < table.size(); ++i) {
198 Hash h = table.hash_at(i);
199 if (!h) {
200 continue;
202 std::bitset<64> b = h;
203 int z = b.count();
204 zeros += 64 - z;
205 ones += z;
208 std::ostringstream stream;
209 stream << get_stat("Table Size", table_size / 1024 / 1024, "Mb");
210 stream << std::endl;
212 stream << get_stat("Entries", table.size());
213 stream << std::endl;
215 stream << get_stat("Usage", table.usage());
216 stream << get_meta(get_percent(table.usage(), table.size()), "%");
217 stream << std::endl;
219 stream << get_stat("0's", get_percent(zeros, 64 * table.usage()), "%");
220 stream << std::endl;
222 stream << get_stat("1's", get_percent(ones, 64 * table.usage()), "%");
223 stream << std::endl;
225 stream << get_stat("Lookups", table.nb_lookups());
226 stream << std::endl;
228 stream << get_stat("Hits", table.nb_hits());
229 stream << get_meta(get_percent(table.nb_hits(),
230 table.nb_lookups()), "%");
231 stream << std::endl;
233 stream << get_stat("Collisions", table.nb_collisions());
234 stream << get_meta(get_percent(table.nb_collisions(),
235 table.nb_lookups()), "%");
236 stream << std::endl;
238 stream << get_stat("Misses", table.nb_misses());
239 stream << get_meta(get_percent(table.nb_misses(),
240 table.nb_lookups()), "%");
241 stream << std::endl;
243 return stream.str();
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();
266 return stream.str();