-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoard.cpp
138 lines (124 loc) · 4.31 KB
/
Board.cpp
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
#include "Board.h"
#include "util.h"
#include <vector>
#include <array>
#include <iostream>
Board::Board(StateVector inpState) {
state = inpState;
/* Define the base anchors and build the bases as diagonally
opposite mirrors.
The black [top-left] bases are:
0,0; 1,0; 2,0; 3,0; 4,0
0,1; 1,1; 2,1; 3,1; 4,1
0,2; 1,2; 2,2; 3,2
0,3; 1,3; 2,3;
0,4; 1,4
The white [bottom-right] bases are:
14,11; 15,11;
13,12; 14,12; 15,12;
12,13; 13,13; 14,13; 15,13;
11,14; 12,14; 13,14; 14,14; 15,14;
11,15; 12,15; 13,15; 14,15; 15,15;
Subtractng each of the top from (15,15) returns the white base coordinates.
*/
int baseAnchors[19][2] = {
{0,0},
{1,0},
{2,0},
{3,0},
{4,0},
{0,1},
{1,1},
{2,1},
{3,1},
{4,1},
{0,2},
{1,2},
{2,2},
{3,2},
{0,3},
{1,3},
{2,3},
{0,4},
{1,4}
};
for (int i = 0; i < 19; i++) {
std::array<int, 2> currWhite = {}, currBlack = {};
for (int j = 0; j < 2; j++) {
currBlack[j] = baseAnchors[i][j];
currWhite[j] = 15 - baseAnchors[i][j];
}
blackBase.push_back(currBlack);
whiteBase.push_back(currWhite);
}
solutions = new std::map<std::array<int, 4>,State*>;
}
PositionsVector Board::getBase(char team) {
return (team == 'B' ? blackBase : whiteBase);
}
/*
Take the first state s, generate its children and their children and so on until "depth" times
If there is a jump, also consider the next "child" states [can snowball!!!]
Handle snowballing by using visited.
However, for each piece, there are upto 8, implying upto 152 moves per level, not counting jumps
This implies that for a depth of 3 moves, you look at 7 million moves. Use alpha beta pruning?
*/
State* Board::generateMinMaxTree(State* parent, int turnCount, PositionsVector argLocations, float alpha, float beta, bool isMax) {
solutions->insert(std::pair<std::array<int, 4>, State*>({}, NULL));
/*
Get the opponent's locations how?
Given your pieces, calculate the appropriate PositionsVector for the other player?
Get the symbol in argLocations[0][0], then get the appropriate PositionVector of the other team?
Also try to incorporate Alpha Beta Pruning here itself to avoid unnecessary expansion
*/
char team = parent->getState()[argLocations[0][1]][argLocations[0][0]];
char opponentTeam = team == 'B' ? 'W' : 'B';
char target = isMax ? team : opponentTeam;
parent->computeScore(target, getBase(target));
// std::cout << "Target score is: " << parent->getScore() << std::endl;
// If we have reached the depth / terminal condition then we shall return the utility of this board
if (turnCount == 0 || parent->getScore() == FLT_MAX || parent->getScore() == -FLT_MAX + 1) {
/*
If isMax is true, then the player is the one making the terminal move, else it's the other player
We need to get the utility only for the terminal state
*/
parent->setAlphaBetaPrediction(parent->getScore());
return parent;
}
// Create all the child states of this parent
parent->setFutureStates(argLocations, team, blackBase, solutions);
// If the node is a MAX expander, set the value to -inf, else set it to inf
float v = isMax ? -FLT_MAX + 1 : FLT_MAX;
// Get all the children
std::vector<State *> children = parent->getChildren();
for (int i = 0; i < children.size(); i++) {
PositionsVector opponentPositions = getPositions(children[i]->getState(), opponentTeam);
children[i] = generateMinMaxTree(children[i], turnCount - 1, opponentPositions, alpha, beta, !isMax);
float result = children[i]->getAlphaBetaPrediction();
/*
Some properties:
If isMax is false, then this is a min expander
Alpha is always less than Beta
For a maxNode, v being larger than beta implies that the parent is NOT going to choose this
For a minNode, v being less than alpha implies the same
*/
if ((isMax && result > v) || (!isMax && result < v)) {
parent->setDesiredChildLoc(i);
// create a 0.9 factor to penalize child labor, i.e.prefer moves that get a result in this move over those
// that get it in the future.
v = result * 0.9;
}
if ((isMax && result >= beta) || (!isMax && result <= alpha)) {
parent->setAlphaBetaPrediction(v);
return parent;
}
if (isMax) {
alpha = max(alpha, result);
} else {
beta = min(beta, result);
}
}
parent->setChildren(children);
parent->setAlphaBetaPrediction(v);
return parent;
}