-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
moveselector.h
executable file
·159 lines (131 loc) · 4.33 KB
/
moveselector.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#ifndef MOVESELECTOR_H
#define MOVESELECTOR_H
#include "constants.h"
#include "board.h"
#include "move.h"
#include "searchinfo.h"
namespace Napoleon
{
class MoveSelector
{
public:
Board& board;
Move moves[Constants::MaxMoves];
Move hashMove;
int count;
MoveSelector(Board&, SearchInfo&);
template<bool>
void Sort(int = 0);
Move First();
Move Next();
void Reset();
Move& operator[](int);
private:
int scores[Constants::MaxMoves];
SearchInfo& info;
int first;
};
inline Move& MoveSelector::operator[](int index)
{
return moves[index];
}
inline Move MoveSelector::First()
{
/*
* TODO: TRY THIS
if (!hashMove.IsNull())
{
for(int i=0; i<count; i++) // do not trust hashMove (may be an illegal move)
{
if (moves[i] == hashMove) return hashMove;
}
}
return Next();
*/
if (!hashMove.IsNull())
return hashMove;
else
return Next();
}
inline void MoveSelector::Reset()
{
first = 0;
}
// make a selection sort on the move array for picking the best untried move
inline Move MoveSelector::Next()
{
if (first == -1)
return First();
int max = first;
if (max >= count)
return Constants::NullMove;
for (auto i=first+1; i<count; i++)
if (scores[i] > scores[max] /*&& moves[i] != hashMove*/)
max = i;
if (max != first)
{
std::swap(moves[first], moves[max]);
std::swap(scores[first], scores[max]);
}
Move move = moves[first++];
if (move != hashMove)
return move;
else
return Next();
}
/// set scores for sorting moves
/// 1) promotions
/// 2) winning captures
/// 3) equal captures
/// 4) killer moves
/// 5) other moves in history heuristic order
/// 6) losing captures
///
/// Every history move has a positive score, so to order them such that they
/// are always after losing captures (which have a score <= 0) we found
/// the minimum score of the captures and the maximum score of the history moves.
/// Then we assing to each history move a score calculated with this formula:
/// Score = HistoryScore - HistoryMax - 3
/// The - 3 factor handle the situation where there are no losing captures,
/// but history moves should still stay after killer moves
/// (which have score -1 and -2). Without that, the best history move
/// would score 0 and would be analyzed before killer moves.
template<bool quiesce>
void MoveSelector::Sort(int ply)
{
using namespace Constants::Piece;
int max = 0;
int historyScore;
for (auto i=0; i<count; i++)
{
if (moves[i].IsPromotion())
{
scores[i] = Constants::Piece::PieceValue[moves[i].PiecePromoted()];
}
else if (board.IsCapture(moves[i]))
{
if (quiesce)
{
Type captured = moves[i].IsEnPassant() ? Type(PieceType::Pawn) : board.PieceOnSquare(moves[i].ToSquare()).Type; // MVV-LVA
scores[i] = PieceValue[captured] - PieceValue[board.PieceOnSquare(moves[i].FromSquare()).Type];
}
else
{
scores[i] = board.See(moves[i]); // SEE
}
}
else if (moves[i] == info.FirstKiller(ply))
scores[i] = - 1;
else if (moves[i] == info.SecondKiller(ply))
scores[i] = - 2;
else if ((historyScore = info.HistoryScore(moves[i], board.SideToMove())) > max)
max = historyScore;
}
for (auto i=0; i<count; i++)
{
if (!board.IsCapture(moves[i]) && moves[i] != info.FirstKiller(ply) && moves[i] != info.SecondKiller(ply))
scores[i] = info.HistoryScore(moves[i], board.SideToMove()) - max - 3;
}
}
}
#endif // MOVESELECTOR_H