1
/*******************************************************************
3
* This file is part of the KDE project "Bovo"
5
* Bovo 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 2, or (at your option)
10
* Bovo 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.
15
* You should have received a copy of the GNU General Public License
16
* along with Bovo; see the file COPYING. If not, write to
17
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
20
********************************************************************/
23
* @file AiBoard implementation
37
#include "dimension.h"
45
AiBoard::AiBoard(const usi width, const usi height,
46
KGameDifficulty::standardLevel skill, Player player)
47
: m_cleanBoard(true), m_player(player), m_skill(skill) {
48
m_dimension = new Dimension(width, height);
52
AiBoard::AiBoard(const Dimension& dimension,
53
KGameDifficulty::standardLevel skill, Player player)
54
: m_cleanBoard(true), m_player(player), m_skill(skill) {
55
m_dimension = new Dimension(dimension.width(), dimension.height());
60
for (int x = 0; x < m_dimension->width(); ++x) {
67
bool AiBoard::empty(const Coord& c) const throw(outOfBounds) {
68
if (!m_dimension->ok(c)) {
71
return m_board[c.x()][c.y()].empty();
74
bool AiBoard::empty(const usi x, const usi y) const throw(outOfBounds) {
75
return empty(Coord(x, y));
78
usi AiBoard::height() const {
79
return m_dimension->height();
82
Coord AiBoard::move() {
84
srand(static_cast<int>(time(0)));
85
usi randX = rand()%(m_dimension->width()/3) + m_dimension->width()/3;
86
usi randY = rand()%(m_dimension->height()/3) + m_dimension->height()/3;
87
return Coord(randX, randY);
89
for (usi x = 0; x < m_dimension->width(); ++x) {
90
for (usi y = 0; y < m_dimension->height(); ++y) {
91
if (m_board[x][y].status()) {
93
setPoints(c, value(c, m_player));
94
addPoints(c, value(c, m_player == X ? O : X));
98
Coord out = evaluate();
102
Coord* AiBoard::moves() {
104
#warning Implement - Coord* AiBoard::moves(const Coord& c)
109
Player AiBoard::player(const Coord& c) const throw(outOfBounds) {
110
if (!m_dimension->ok(c)) {
113
return m_board[c.x()][c.y()].player();
116
Player AiBoard::player(const usi x, const usi y) const throw(outOfBounds) {
117
return player(Coord(x, y));
120
bool AiBoard::setPlayer(const Move& move)
121
throw(busy, gameover, notValidPlayer) {
122
m_cleanBoard = false;
124
m_board[move.coord().x()][move.coord().y()].setPlayer(move.player());
125
if (win(move.coord())) {
132
void AiBoard::setSkill(KGameDifficulty::standardLevel skill) {
136
usi AiBoard::width() const {
137
return m_dimension->width();
140
/* secret helper functions */
142
Coord next(const Coord& c, usi dir) {
150
} else if (dir & RIGHT) {
155
} else if (dir & DOWN) {
161
bool cmp(const pair<uli, Coord> a, const pair<uli, Coord> b) {
162
return a.first > b.first;
165
/* Private methods */
167
Coord AiBoard::evaluate() const {
168
std::vector<std::pair<uli, Coord> > v, v2, v3;
169
for (int x = 0; x < m_dimension->width(); ++x) {
170
for (int y = 0; y < m_dimension->height(); ++y) {
171
v.push_back(make_pair(points(Coord(x, y)), Coord(x, y)));
174
sort(v.begin(), v.end(), cmp);
175
uli max = v.begin()->first;
176
for (vector<pair<uli, Coord> >::const_iterator it = v.begin();
177
it != v.end(); ++it) {
178
bool doBreak = false;
180
case KGameDifficulty::Impossible: // @TODO: Implement Impossible
181
case KGameDifficulty::VeryHard: //@TODO: Implement Very Hard
182
case KGameDifficulty::Hard:
183
if (it->first == max) {
189
case KGameDifficulty::Medium:
190
if (it->first * 1.2 >= max) {
193
random_shuffle(v2.begin(), v2.end());
194
return v2.begin()->second;
197
case KGameDifficulty::Easy:
198
if (it->first * 2 >= max) {
201
random_shuffle(v2.begin(), v2.end());
202
return v2.begin()->second;
205
case KGameDifficulty::VeryEasy:
206
if (it->first * 4 >= max) {
209
random_shuffle(v2.begin(), v2.end());
210
return v2.begin()->second;
213
case KGameDifficulty::RidiculouslyEasy:
214
default: // in case the gui sets the level to an illegal value
215
if (it->first * 7 >= max) {
218
random_shuffle(v2.begin(), v2.end());
219
return v2.begin()->second;
227
if (v2.size() == 0) {
229
} else if (v2.size() == 1) {
230
return v2.begin()->second;
232
for (vector<pair<uli, Coord> >::const_iterator it = v2.begin();
233
it != v2.end(); ++it) {
234
v3.push_back(make_pair(value2(it->second), it->second));
236
sort(v3.begin(), v3.end(), cmp);
238
random_shuffle(v3.begin(), v3.end());
240
return v3.begin()->second;
243
uli AiBoard::points(const Coord& c) const throw(outOfBounds) {
244
if (!m_dimension->ok(c)) {
247
return m_board[c.x()][c.y()].points();
250
void AiBoard::addPoints(const Coord& c, uli points) throw(outOfBounds) {
251
if (!m_dimension->ok(c)) {
254
m_board[c.x()][c.y()].setPoints(m_board[c.x()][c.y()].points() + points);
257
void AiBoard::setPoints(const Coord& c, uli points) throw(outOfBounds) {
258
if (!m_dimension->ok(c)) {
261
m_board[c.x()][c.y()].setPoints(points);
262
m_board[c.x()][c.y()].setStatus(false);
265
void AiBoard::setup() {
267
m_board = new AiSquare*[m_dimension->width()];
268
for (int x = 0; x < m_dimension->width(); ++x) {
269
m_board[x] = new AiSquare[m_dimension->height()];
273
uli AiBoard::value(const Coord& c, const usi pl) const {
277
usi oppositePlayer = (pl==1?2:1);
285
for (int dir = 0; dir < 4; ++dir) {
286
for (int i = 1; i <= 5; ++i) {
292
for (int diff = 5-i; diff > 0-i; --diff) {
296
tmp = Coord(c.x()-diff, c.y());
299
tmp = Coord(c.x(), c.y()-diff);
302
tmp = Coord(c.x()-diff, c.y()-diff);
305
tmp = Coord(c.x()+diff, c.y()-diff);
308
if (m_dimension->ok(tmp)) {
309
if (player(tmp) == pl) {
313
} else if (player(tmp) == oppositePlayer) {
334
tmpPoint *= (m_skill == KGameDifficulty::RidiculouslyEasy ? 7 : 231);
336
tmpPoint *= (m_skill == KGameDifficulty::VeryEasy ? 21 :
337
(m_skill == KGameDifficulty::RidiculouslyEasy ? 12 : 231));
339
tmpPoint *= (m_skill == KGameDifficulty::VeryEasy ? 21 : 231 );
342
tmpPoint *= m_skill == KGameDifficulty::RidiculouslyEasy ? 3 : 1;
347
if (pl == m_player && m_skill != KGameDifficulty::RidiculouslyEasy
348
&& m_skill != KGameDifficulty::VeryEasy) {
351
if (empty < 2 && await > 0 && leftsideEmpty > 0) {
360
uli AiBoard::value2(const Coord& c) const {
364
Coord tmp(c.x(), c.y());
366
for (usi u = 1; u < 3; ++u) {
367
for (usi i = 0; i < 4; ++i) {
371
tmp = Coord(c.x()-q, c.y());
374
tmp = Coord(c.x(), c.y()-q);
377
tmp = Coord(c.x()-q, c.y()-q);
380
tmp = Coord(c.x()+q, c.y()-q);
383
test = m_dimension->ok(tmp);
385
test = player(tmp) == u;
397
tmp = Coord(c.x()+q, c.y());
400
tmp = Coord(c.x(), c.y()+q);
403
tmp = Coord(c.x()+q, c.y()+q);
406
tmp = Coord(c.x()-q, c.y()+q);
409
test = m_dimension->ok(tmp);
411
test = player(tmp) == u;
440
bool AiBoard::win(const Coord& c) const {
456
for (int i = 0; i < 4; ++i) {
458
Coord tmp = next(c, DIR[2*i]);
459
while (m_dimension->ok(tmp) && player(tmp) == p) {
461
tmp = next(tmp, DIR[2*i]);
463
tmp = next(c, DIR[2*i+1]);
464
while (m_dimension->ok(tmp) && player(tmp) == p) {
466
tmp = next(tmp, DIR[2*i+1]);
475
void AiBoard::zero(const Coord& c) {
476
usi minX = c.x()-5 < 0 ? 0 : c.x()-5;
477
usi maxX = c.x()+5 > m_dimension->width()-1 ? m_dimension->width()-1 : c.x()+5;
478
usi minY = c.y()-5 < 0 ? 0 : c.y()-5;
479
usi maxY = c.y()+5 > m_dimension->height()-1 ? m_dimension->height()-1 : c.y()+5;
480
for (int x = minX; x <= maxX; ++x) {
481
for (int y = minY; y <= maxY; ++y) {
482
m_board[x][y].setStatus(true);