Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 pmbaty 1
/*
2
    Texel - A UCI chess engine.
3
    Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
4
 
5
    This program is free software: you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation, either version 3 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
 
19
/*
20
 * tuigame.cpp
21
 *
22
 *  Created on: Mar 4, 2012
23
 *      Author: petero
24
 */
25
 
26
#include "tuigame.hpp"
27
#include "uciprotocol.hpp"
28
#include "textio.hpp"
29
#include "evaluate.hpp"
30
#include "computerPlayer.hpp"
31
 
32
#include <iostream>
33
#include <fstream>
34
#include <iomanip>
35
 
36
TUIGame::TUIGame(const std::shared_ptr<Player>& whitePlayer,
37
                 const std::shared_ptr<Player>& blackPlayer)
38
    : Game(whitePlayer, blackPlayer) {
39
}
40
 
41
bool
42
TUIGame::handleCommand(const std::string& moveStr) {
43
    if (Game::handleCommand(moveStr))
44
        return true;
45
    if (startsWith(moveStr, "testsuite ")) {
46
        std::string testSuiteCmd = moveStr.substr(moveStr.find_first_of(' ') + 1);
47
        handleTestSuite(testSuiteCmd);
48
        return true;
49
    } else if (moveStr == "uci") {
50
        whitePlayer.reset();
51
        blackPlayer.reset();
52
        UCIProtocol::main(true);
53
        exit(0);
54
        return false;
55
    } else if (moveStr == "help") {
56
        showHelp();
57
        return true;
58
    }
59
 
60
    return false;
61
}
62
 
63
void
64
TUIGame::showHelp() {
65
    std::cout << "Enter a move, or one of the following special commands:" << std::endl;
66
    std::cout << "  new             - Start a new game" << std::endl;
67
    std::cout << "  undo            - Undo last half-move" << std::endl;
68
    std::cout << "  redo            - Redo next half-move" << std::endl;
69
    std::cout << "  swap            - Swap sides" << std::endl;
70
    std::cout << "  go              - Same as swap" << std::endl;
71
    std::cout << "  list            - List all moves in current game" << std::endl;
72
    std::cout << "  setpos FEN      - Set a position using a FEN string" << std::endl;
73
    std::cout << "  getpos          - Print current position in FEN notation" << std::endl;
74
    std::cout << "  draw rep [move] - Claim draw by repetition" << std::endl;
75
    std::cout << "  draw 50 [move]  - Claim draw by 50-move rule" << std::endl;
76
    std::cout << "  draw offer move - Play move and offer draw" << std::endl;
77
    std::cout << "  draw accept     - Accept a draw offer" << std::endl;
78
    std::cout << "  resign          - Resign the current game" << std::endl;
79
    std::cout << "  testsuite filename maxtime" << std::endl;
80
    std::cout << "  book on|off     - Turn opening book on/off" << std::endl;
81
    std::cout << "  time t          - Set computer thinking time, ms" << std::endl;
82
    std::cout << "  perft d         - Run perft test to depth d" << std::endl;
83
    std::cout << "  uci             - Switch to uci protocol." << std::endl;
84
    std::cout << "  help            - Show this help" << std::endl;
85
    std::cout << "  quit            - Terminate program" << std::endl;
86
}
87
 
88
void
89
TUIGame::handleTestSuite(const std::string& cmd) {
90
    std::ifstream fr;
91
    int lineNo = -1;
92
    try {
93
        size_t idx = cmd.find_first_of(' ');
94
        if (idx == cmd.npos)
95
            return;
96
        std::string filename(cmd.substr(0, idx));
97
        std::string timeStr(cmd.substr(idx + 1));
98
        int timeLimit;
99
        if (!str2Num(timeStr, timeLimit)) {
100
            std::cout << "Error parsing number: " << timeStr << std::endl;
101
            return;
102
        }
103
//        std::cout << "file:" << filename << " time:" << timeStr << " (" << timeLimit << ")" << std::endl;
104
        fr.open(filename.c_str());
105
        std::shared_ptr<Player> pl = whitePlayer->isHumanPlayer() ? blackPlayer : whitePlayer;
106
        if (pl->isHumanPlayer()) {
107
            std::cout << "No computer player available" << std::endl;
108
            return;
109
        }
110
        std::shared_ptr<ComputerPlayer> cp = std::static_pointer_cast<ComputerPlayer>(pl);
111
        int numRight = 0;
112
        int numTotal = 0;
113
        std::string line;
114
        lineNo = 0;
115
        while (getline(fr, line).good()) {
116
            lineNo++;
117
            if (startsWith(line, "#") || (line.length() == 0))
118
                continue;
119
            size_t idx1 = line.find(" bm ");
120
            if (idx1 == line.npos) {
121
                std::cout << "Parse error, line:" << lineNo << std::endl;
122
                return;
123
            }
124
            std::string fen = line.substr(0, idx1);
125
            size_t idx2 = line.find(";", idx1);
126
            if (idx2 == line.npos) {
127
                std::cout << "Parse error, line:" << lineNo << std::endl;
128
                return;
129
            }
130
            std::string bm = line.substr(idx1+4, idx2 - (idx1+4));
131
//            std::cout << "Line " << std::setw(3) << lineNo << ": fen:" << fen << " bm:" << bm << std::endl;
132
            Position testPos = TextIO::readFEN(fen);
133
            cp->clearTT();
134
            std::pair<Move, std::string> ret = cp->searchPosition(testPos, timeLimit);
135
            Move sm = ret.first;
136
            std::string PV = ret.second;
137
            Move m(sm);
138
            std::vector<std::string> answers;
139
            splitString(bm, answers);
140
            bool correct = false;
141
            for (size_t i = 0; i < answers.size(); i++) {
142
                const std::string& a = answers[i];
143
                Move am(TextIO::stringToMove(testPos, a));
144
                if (am.isEmpty())
145
                    throw ChessParseError("Invalid move " + a);
146
                if (am.equals(m)) {
147
                    correct = true;
148
                    break;
149
                }
150
            }
151
            if (correct)
152
                numRight++;
153
            numTotal++;
154
            std::cout << std::setw(3) << lineNo
155
                      << ' ' << std::setw(6) << TextIO::moveToString(testPos, sm, false)
156
                      << ' ' << std::setw(6) << sm.score()
157
                      << ' ' << (correct ? 1 : 0)
158
                      << ' ' << std::setw(3) << numRight
159
                      << '/' << std::setw(3) << numTotal
160
                      << ' ' << bm << " : " << PV << std::endl;
161
        }
162
        fr.close();
163
    } catch (const std::ifstream::failure& ex) {
164
        std::cout << "IO error: " << ex.what() << std::endl;
165
    } catch (const ChessParseError& cpe) {
166
        std::cout << "Parse error, line " << lineNo << ": " << cpe.what() << std::endl;
167
    }
168
}
169
 
170
void
171
TUIGame::play() {
172
    handleCommand("new");
173
    while (true) {
174
        // Print last move
175
        if (currentMove > 0) {
176
            Position prevPos(getPos());
177
            prevPos.unMakeMove(moveList[currentMove - 1], uiInfoList[currentMove - 1]);
178
            std::string moveStr= TextIO::moveToString(prevPos, moveList[currentMove - 1], false);
179
            if (haveDrawOffer())
180
                moveStr += " (offer draw)";
181
            std::cout << "Last move: " << prevPos.getFullMoveCounter()
182
                    << (prevPos.isWhiteMove() ? "." : "...")
183
                    << ' ' << moveStr << std::endl;
184
        }
185
        /*
186
        {
187
            std::stringstream ss;
188
            ss << "Hash: " << std::hex << std::setw(16) << std::setfill('0') << pos.zobristHash();
189
            std::cout << ss.str() << std::endl;
190
        }
191
        */
192
        {
193
            auto et = Evaluate::getEvalHashTables();
194
            Evaluate eval(*et);
195
            int evScore = eval.evalPos(getPos()) * (getPos().isWhiteMove() ? 1 : -1);
196
            std::stringstream ss;
197
            ss.precision(2);
198
            ss << std::fixed << "Eval: " << (evScore / 100.0);
199
            std::cout << ss.str() << std::endl;
200
        }
201
 
202
        // Check game state
203
        std::cout << TextIO::asciiBoard(getPos());
204
        std::string stateStr = getGameStateString();
205
        if (stateStr.length() > 0)
206
            std::cout << stateStr << std::endl;
207
        if (getGameState() != Game::ALIVE)
208
            activateHumanPlayer();
209
 
210
        // Get command from current player and act on it
211
        std::shared_ptr<Player> pl = getPos().isWhiteMove() ? whitePlayer : blackPlayer;
212
        std::vector<Position> posList;
213
        getHistory(posList);
214
        std::string moveStr = pl->getCommand(getPos(), haveDrawOffer(), posList);
215
        if (moveStr == "quit")
216
            return;
217
        bool ok = processString(moveStr);
218
        if (!ok)
219
            std::cout << "Invalid move: " << moveStr << std::endl;
220
    }
221
}