Introducing Lazy Move Generation
[purplehaze.git] / src / output.cpp
blob6076920af8044c516fdadfb0160bd5a315d34766
1 /* PurpleHaze 2.0.0
2 * Copyright (C) 2007-2011 Vincent Ollivier
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <assert.h>
19 #include <iostream>
20 #include <iomanip>
21 #include <string>
22 #include <sstream>
23 #include <bitset>
25 #include "game.h"
27 using namespace std;
29 #define WIDE 10
31 void Game::print_thinking_header() {
32 if (!output_thinking) return;
33 cout << setw(4) << "ply";
34 cout << setw(WIDE) << "score";
35 cout << setw(WIDE) << "time";
36 cout << setw(WIDE) << "nodes";
37 cout << setw(WIDE) << "pv";
38 cout << endl;
41 void Game::print_thinking(int depth, int score, Move m) {
42 if (!output_thinking) return;
43 cout << setw(4) << depth;
44 cout << setw(WIDE) << score;
45 cout << setw(WIDE) << time.get_elapsed_time();
46 cout << setw(WIDE) << nodes_count;
47 cout << setw(WIDE - 3) << " ";
48 int ply = current_node().get_ply();
49 if (ply % 2 != 0) cout << 1 + (ply / 2) << ". ...";
50 //cout << m << endl;
51 assert(is_legal(m) || assert_msg(
52 endl << board << endl <<
53 "m = " << output_move(m) << " (" << m << ")" << endl <<
54 "m is en passant: " << m.is_en_passant()
55 ));
57 cout << output_principal_variation(depth, m) << endl;
60 string Game::output_principal_variation(int depth, Move m) {
61 ostringstream stream;
62 stream << " ";
63 int ply = current_node().get_ply();
64 if (ply % 2 == 0) stream << 1 + (ply / 2) << ". ";
65 stream << output_move(m);
66 Node pos = current_node();
67 make_move(m);
68 if (is_check(current_node().get_turn_color())) stream << "+";
70 // Find next move in TT
71 Transposition trans = tt.lookup(current_node().hash());
73 cout << endl;
74 cout << "value=" << trans.get_value();
75 cout << ", bound=" << trans.get_bound();
76 cout << ", depth=" << trans.get_depth();
77 cout << ", move=" << trans.get_best_move() << endl;
79 Move move = trans.get_best_move();
80 if (depth > 0 && is_legal(move) && trans.get_bound() < 3) {
81 stream << output_principal_variation(depth - 1, move);
84 undo_move(m);
85 assert(pos.hash() == current_node().hash());
86 return stream.str();
89 string Game::output_move(Move m) {
90 ostringstream stream;
92 // Castling
93 if (m.is_castle()) {
94 if (m.get_castle_side() == QUEEN) stream << "O-";
95 return stream.str() + "O-O";
98 // Type of piece
99 Square from = m.get_orig();
100 Piece p = board.get_piece(from);
101 PieceType t = p.get_type();
102 if (t > PAWN) stream << Piece(WHITE, t); // Upper case
104 // Capture
105 if (m.is_capture()) {
106 if (t == PAWN) stream << char('a' + m.get_orig_file());
107 else { // Disambiguation
108 Color c = current_node().get_turn_color(); // FIXME invert color
109 Square to = m.get_dest();
110 for (int i = 0; i < pieces.get_nb_pieces(c, t); ++i) {
111 Square s = pieces.get_position(c, t, i);
112 if (s != from && board.can_attack(t, s, to)) {
113 stream << char('a' + m.get_orig_file());
114 break;
118 stream << "x";
121 // Destination
122 stream << output_square(m.get_dest_file(), m.get_dest_rank());
124 // Promotion
125 if (m.is_promotion()) {
126 stream << "=" << Piece(WHITE, m.get_promotion_type());
129 return stream.str();
132 string Game::output_square(File f, Rank r) {
133 ostringstream stream;
134 stream << char('a' + f) << char('1' + r);
135 return stream.str();
138 void Game::print_tt_stats() {
139 long zeros = 0;
140 long ones = 0;
141 for (int i = 0; i < tt.size(); ++i) {
142 if (tt.at(i).is_empty()) continue;
143 Hash h = tt.at(i).get_hash();
144 bitset<64> b = h;
145 int z = b.count();
146 //cout << "0: " << 64 - z << ", 1: " << z << endl;
147 zeros += 64 - z;
148 ones += z;
151 cout << "Zobrist: " << hex << current_node().hash() << dec << endl;
152 cout << "TT Size: " << TT_SIZE / 1024 / 1024 << "Mb" << endl;
153 cout << "Entries: " << tt.size() << endl;
154 cout << "Usage: " << tt.get_usage();
155 float percent_usage = (100 * tt.get_usage()) / float(tt.size());
156 cout << " (" << percent_usage << "%)" << endl;
157 float percent_zeros = (100.0 * zeros) / (64.0 * tt.get_usage());
158 cout << "0's: " << percent_zeros << "%" << endl;
159 float percent_ones = (100.0 * ones) / (64.0 * tt.get_usage());
160 cout << "1's: " << percent_ones << "%" << endl;
162 cout << "Lookups: " << tt.get_nb_lookups() << endl;
164 cout << "Hits: " << tt.get_nb_hits();
165 float percent_hits = (100 * tt.get_nb_hits()) /
166 float(tt.get_nb_lookups());
167 cout << " (" << percent_hits << "%)" << endl;
169 cout << "Index Collisions: " << tt.get_nb_collisions();
170 float percent_collisions = (100 * tt.get_nb_collisions()) /
171 float(tt.get_nb_lookups());
172 cout << " (" << percent_collisions << "%)" << endl;
174 cout << "Misses: " << tt.get_nb_misses();
175 float percent_misses = (100 * tt.get_nb_misses()) /
176 float(tt.get_nb_lookups());
177 cout << " (" << percent_misses << "%)" << endl;