Mocno poprawiony algorytm minimax i wykrywanie ruchów
This commit is contained in:
23
inc/board.hh
23
inc/board.hh
@@ -28,7 +28,10 @@ struct Movement
|
|||||||
bool operator==(const Movement& b) { return ((begin == b.begin) && (end == b.end)); }
|
bool operator==(const Movement& b) { return ((begin == b.begin) && (end == b.end)); }
|
||||||
|
|
||||||
// Wypisywanie ruchu do terminala
|
// Wypisywanie ruchu do terminala
|
||||||
void display() { std::cout << begin.x << ", " << begin.y << "\t->\t" << end.x << ", " << end.y << std::endl; }
|
void display() { begin.display(); std::cout<< "\t->\t"; end.display(); std::cout << std::endl; }
|
||||||
|
|
||||||
|
// Zwraca wektor ruchu
|
||||||
|
Vector getVector() { return end-begin; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Klasa implementująca planszę
|
// Klasa implementująca planszę
|
||||||
@@ -42,6 +45,9 @@ private:
|
|||||||
// Zaznaczone kafelki na mapie(ułatwienie dla gracza)
|
// Zaznaczone kafelki na mapie(ułatwienie dla gracza)
|
||||||
std::list<Vector> selected_tiles;
|
std::list<Vector> selected_tiles;
|
||||||
|
|
||||||
|
// Zaznaczony ruch na mapie
|
||||||
|
bool is_selected_movement;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Konstruktor inicjujący planszę
|
// Konstruktor inicjujący planszę
|
||||||
@@ -63,9 +69,15 @@ public:
|
|||||||
// Przesuń pionek na określoną pozycję
|
// Przesuń pionek na określoną pozycję
|
||||||
bool movePawn(Movement movement);
|
bool movePawn(Movement movement);
|
||||||
|
|
||||||
// Czy ruch jest możliwy (czy dana pozycja jest osiągalna)
|
// Pobierz ilość białych pionków
|
||||||
bool isMovementPossible(Movement movement);
|
unsigned int getNumberOfWhitePawns() const;
|
||||||
|
|
||||||
|
// Pobierz ilość czarnych pionków
|
||||||
|
unsigned int getNumberOfBlackPawns() const;
|
||||||
|
|
||||||
|
// Promuj na damki te pionki, które doszły na linię promocji
|
||||||
|
void upgrade();
|
||||||
|
|
||||||
// Czy bicie z danej pozycji jest możliwe
|
// Czy bicie z danej pozycji jest możliwe
|
||||||
bool isPossibleBeating(Vector position);
|
bool isPossibleBeating(Vector position);
|
||||||
|
|
||||||
@@ -96,8 +108,11 @@ public:
|
|||||||
// Zaznacz wybrane kafelki na mapie
|
// Zaznacz wybrane kafelki na mapie
|
||||||
void selectTiles(std::list<Vector> tiles) { selected_tiles = tiles; }
|
void selectTiles(std::list<Vector> tiles) { selected_tiles = tiles; }
|
||||||
|
|
||||||
|
// Zaznacz ruch na mapie
|
||||||
|
void selectMovement(Movement movement);
|
||||||
|
|
||||||
// Odznacz kafelki na mapie
|
// Odznacz kafelki na mapie
|
||||||
void deselectTiles() { selected_tiles.clear(); }
|
void deselectTiles() { is_selected_movement = false; selected_tiles.clear(); }
|
||||||
|
|
||||||
// Wyświetl zawartość planszy na standardowym wyjściu
|
// Wyświetl zawartość planszy na standardowym wyjściu
|
||||||
void display();
|
void display();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
const std::string GAME_TITLE = "Warcaby";
|
const std::string GAME_TITLE = "Warcaby";
|
||||||
|
|
||||||
// Ilość pól w każdym wymiarze
|
// Ilość pól w każdym wymiarze
|
||||||
const int TILES_COUNT = 10;
|
const int TILES_COUNT = 8;
|
||||||
|
|
||||||
// Długość boku pojedynczego kafelka(który jest kwadratem)
|
// Długość boku pojedynczego kafelka(który jest kwadratem)
|
||||||
const int TILE_SIZE = 64;
|
const int TILE_SIZE = 64;
|
||||||
|
|||||||
24
inc/game.hh
24
inc/game.hh
@@ -25,6 +25,14 @@ enum Player
|
|||||||
PL_AI
|
PL_AI
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Typ wyliczeniowy implementujący stany gry
|
||||||
|
enum GameState
|
||||||
|
{
|
||||||
|
GS_PAUSED,
|
||||||
|
GS_RUNNING,
|
||||||
|
GS_WIN,
|
||||||
|
GS_LOSS
|
||||||
|
};
|
||||||
|
|
||||||
// Klasa gry
|
// Klasa gry
|
||||||
class Game
|
class Game
|
||||||
@@ -35,6 +43,9 @@ class Game
|
|||||||
// Plansza do gry w warcaby
|
// Plansza do gry w warcaby
|
||||||
Board board;
|
Board board;
|
||||||
|
|
||||||
|
// Stan gry
|
||||||
|
GameState game_state;
|
||||||
|
|
||||||
// Zaznaczony pionek
|
// Zaznaczony pionek
|
||||||
Vector selected;
|
Vector selected;
|
||||||
|
|
||||||
@@ -43,9 +54,6 @@ class Game
|
|||||||
|
|
||||||
// Tura(czy gracz, czy AI)
|
// Tura(czy gracz, czy AI)
|
||||||
Color round;
|
Color round;
|
||||||
|
|
||||||
// Flaga oznaczająca sekwencję ruchów(aby gracz nie mógł zmienić pionka w trakcie gry)
|
|
||||||
bool movements_sequence;
|
|
||||||
|
|
||||||
// Punkty gracza
|
// Punkty gracza
|
||||||
int player_score;
|
int player_score;
|
||||||
@@ -83,6 +91,12 @@ private:
|
|||||||
|
|
||||||
// Rysuje HUD (czyli ilość punktów etc.)
|
// Rysuje HUD (czyli ilość punktów etc.)
|
||||||
void drawHUD();
|
void drawHUD();
|
||||||
|
|
||||||
|
// Aktualizuj stan gry
|
||||||
|
void gameUpdate();
|
||||||
|
|
||||||
|
// Wyświetl ekran końcowy
|
||||||
|
void displayTheEnd();
|
||||||
|
|
||||||
// Główna pętla gry
|
// Główna pętla gry
|
||||||
void loop();
|
void loop();
|
||||||
@@ -90,7 +104,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
// Konstruktor inicjalizujący parametry gry i wyzwalający pętlę główną gry
|
// Konstruktor inicjalizujący parametry gry i wyzwalający pętlę główną gry
|
||||||
Game();
|
// player - kolor gracza (zawsze biały kolor zaczyna)
|
||||||
|
// ai - poziom AI (głębokość przeszukiwania drzewa gry przez algorytm minimax)
|
||||||
|
Game(Color player, int ai);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ private:
|
|||||||
|
|
||||||
// Funkcja zwraca kolor kolejnego gracza z drzewa minimaks
|
// Funkcja zwraca kolor kolejnego gracza z drzewa minimaks
|
||||||
Color getColorFromDepth(int depth);
|
Color getColorFromDepth(int depth);
|
||||||
|
public:
|
||||||
// Funkcja heurystyczna
|
// Funkcja heurystyczna
|
||||||
int evaluate(Board& board, const Color& color);
|
int evaluate(Board& board, const Color& color);
|
||||||
public:
|
public:
|
||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
int alphabeta(Board board, int depth, int alpha, int beta, Movement& best_movement);
|
int alphabeta(Board board, int depth, int alpha, int beta, Movement& best_movement);
|
||||||
|
|
||||||
// Funkcja startowa algorytmu minimax z cięciem alfa-beta
|
// Funkcja startowa algorytmu minimax z cięciem alfa-beta
|
||||||
Movement minimax(Board board);
|
Movement getBestMovement(Board board);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
16
inc/misc.hh
16
inc/misc.hh
@@ -1,6 +1,7 @@
|
|||||||
#ifndef MISC_HH
|
#ifndef MISC_HH
|
||||||
#define MISC_HH
|
#define MISC_HH
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
@@ -10,13 +11,13 @@
|
|||||||
struct Vector
|
struct Vector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
unsigned int x;
|
int x;
|
||||||
unsigned int y;
|
int y;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Konstruktor tworzący parę (_x, _y)
|
// Konstruktor tworzący parę (_x, _y)
|
||||||
Vector(unsigned int _x, unsigned int _y) : x(_x), y(_y) {}
|
Vector(int _x, int _y) : x(_x), y(_y) {}
|
||||||
|
|
||||||
// Konstruktor tworzący parę (x, y) na podstawie rzeczywistych współrzędnych
|
// Konstruktor tworzący parę (x, y) na podstawie rzeczywistych współrzędnych
|
||||||
Vector(const RealVector& real_position) : x(real_position.x/TILE_SIZE), y(real_position.y/TILE_SIZE) {}
|
Vector(const RealVector& real_position) : x(real_position.x/TILE_SIZE), y(real_position.y/TILE_SIZE) {}
|
||||||
@@ -41,11 +42,20 @@ public:
|
|||||||
Vector operator*=(int a) { return *this = *this*a; }
|
Vector operator*=(int a) { return *this = *this*a; }
|
||||||
Vector operator*=(float a) { return *this = *this*a; }
|
Vector operator*=(float a) { return *this = *this*a; }
|
||||||
|
|
||||||
|
// Dzielenie wektora przez liczbę
|
||||||
|
Vector operator/(int a) { return Vector(x/a, y/a); }
|
||||||
|
Vector operator/(float a) { return Vector(x/a, y/a); }
|
||||||
|
Vector operator/=(int a) { return *this = *this/a; }
|
||||||
|
Vector operator/=(float a) { return *this = *this/a; }
|
||||||
|
|
||||||
// Porównanie wektorów
|
// Porównanie wektorów
|
||||||
bool operator==(Vector v) { return ((x == v.x) && (y == v.y)); }
|
bool operator==(Vector v) { return ((x == v.x) && (y == v.y)); }
|
||||||
|
|
||||||
// Norma w przestrzeni Manhattan
|
// Norma w przestrzeni Manhattan
|
||||||
int manhattanNorm() const { return abs(x) + abs(y); }
|
int manhattanNorm() const { return abs(x) + abs(y); }
|
||||||
|
|
||||||
|
// Wyświetl wektor
|
||||||
|
void display() const { std::cout << "(" << x << ", " << y << ")"; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ enum Color
|
|||||||
CL_BLACK
|
CL_BLACK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Zwróć kolor przeciwny do argumentu
|
||||||
|
inline Color getOpposedColor(Color color)
|
||||||
|
{
|
||||||
|
if(color == CL_WHITE) return CL_BLACK;
|
||||||
|
else return CL_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
// Klasa reprezentująca pionek
|
// Klasa reprezentująca pionek
|
||||||
class Pawn : public Object
|
class Pawn : public Object
|
||||||
{
|
{
|
||||||
|
|||||||
643
src/board.cpp
643
src/board.cpp
@@ -1,413 +1,458 @@
|
|||||||
#include "../inc/board.hh"
|
#include "../inc/board.hh"
|
||||||
|
|
||||||
Board::Board()
|
Board::Board() : is_selected_movement(false)
|
||||||
{
|
{
|
||||||
// Czyścimy całą tablicę
|
// Czyścimy całą tablicę
|
||||||
for(int i=0; i<TILES_COUNT; ++i) for(int j=0; j<TILES_COUNT; ++j) board[i][j] = NULL;
|
for(int i=0; i<TILES_COUNT; ++i) for(int j=0; j<TILES_COUNT; ++j) board[i][j] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::initBoard()
|
void Board::initBoard()
|
||||||
{
|
{
|
||||||
// Tworzymy czarne pionki
|
// Wyliczamy ilość rzędów w zależności od rozmiaru planszy
|
||||||
for(int i=1; i<TILES_COUNT; i=i+2) createPawn(Vector(i, 0), CL_BLACK);
|
for(int n=0; n<(TILES_COUNT/2 - 1); ++n)
|
||||||
for(int i=0; i<TILES_COUNT; i=i+2) createPawn(Vector(i, 1), CL_BLACK);
|
{
|
||||||
for(int i=1; i<TILES_COUNT; i=i+2) createPawn(Vector(i, 2), CL_BLACK);
|
// Tworzymy czarne pionki
|
||||||
|
for(int i=!(n%2); i<TILES_COUNT; i=i+2) createPawn(Vector(i, n), CL_BLACK);
|
||||||
// Tworzymy białe pionki
|
|
||||||
for(int i=0; i<TILES_COUNT; i=i+2) createPawn(Vector(i, TILES_COUNT-1), CL_WHITE);
|
|
||||||
for(int i=1; i<TILES_COUNT; i=i+2) createPawn(Vector(i, TILES_COUNT-2), CL_WHITE);
|
|
||||||
for(int i=0; i<TILES_COUNT; i=i+2) createPawn(Vector(i, TILES_COUNT-3), CL_WHITE);
|
|
||||||
|
|
||||||
createPawn(Vector(5, 4), CL_WHITE);
|
|
||||||
// createPawn(Vector(4, 4), CL_BLACK);
|
|
||||||
// createPawn(Vector(5, 3), CL_BLACK);
|
|
||||||
// createPawn(Vector(6, 4), CL_BLACK);
|
|
||||||
// createPawn(Vector(5, 5), CL_BLACK);
|
|
||||||
board[5][4]->upgrade();
|
|
||||||
|
|
||||||
|
// Tworzymy białe pionki
|
||||||
|
for(int i=(n%2); i<TILES_COUNT; i=i+2) createPawn(Vector(i, TILES_COUNT-n-1), CL_WHITE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pawn* Board::createPawn(Vector position, Color color)
|
Pawn* Board::createPawn(Vector position, Color color)
|
||||||
{
|
{
|
||||||
// Jeżeli nie istnieje w tym miejscu pionek, to go tworzymy
|
// Jeżeli nie istnieje w tym miejscu pionek, to go tworzymy
|
||||||
if(!board[position.x][position.y])
|
if(!board[position.x][position.y])
|
||||||
board[position.x][position.y] = new Pawn(position, color);
|
board[position.x][position.y] = new Pawn(position, color);
|
||||||
|
|
||||||
// Zwracamy istniejący w tym miejscu pionek (dopiero co utworzony, lub isntiejący wcześniej)
|
// Zwracamy istniejący w tym miejscu pionek (dopiero co utworzony, lub isntiejący wcześniej)
|
||||||
return board[position.x][position.y];
|
return board[position.x][position.y];
|
||||||
}
|
}
|
||||||
|
|
||||||
Pawn* Board::getPawn(Vector position)
|
Pawn* Board::getPawn(Vector position)
|
||||||
{
|
{
|
||||||
return board[position.x][position.y];
|
return board[position.x][position.y];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Board::movePawn(Movement movement)
|
bool Board::movePawn(Movement movement)
|
||||||
{
|
{
|
||||||
// Pomocnicze wektory
|
// Pomocnicze wektory
|
||||||
Vector& position = movement.begin;
|
Vector& position = movement.begin;
|
||||||
Vector& target = movement.end;
|
Vector& target = movement.end;
|
||||||
|
|
||||||
// Jeżeli na pozycji startowej nie ma pionka
|
|
||||||
if(!getPawn(position)) return false;
|
|
||||||
|
|
||||||
// Jeżeli na pozycji docelowej jest pionek(miejsce zajęte)
|
// Jeżeli na pozycji startowej nie ma pionka
|
||||||
if(getPawn(target)) return false;
|
if(!getPawn(position)) return false;
|
||||||
|
|
||||||
// Przesuwamy pionek na planszy
|
// Jeżeli na pozycji docelowej jest pionek(miejsce zajęte)
|
||||||
board[target.x][target.y] = board[position.x][position.y];
|
if(getPawn(target)) return false;
|
||||||
board[position.x][position.y] = NULL;
|
|
||||||
|
|
||||||
// Aktualizujemy informację o pozycji w pionku
|
// Przesuwamy pionek na planszy
|
||||||
board[target.x][target.y]->setPosition(target);
|
board[target.x][target.y] = board[position.x][position.y];
|
||||||
|
board[position.x][position.y] = NULL;
|
||||||
|
|
||||||
// Zwracamy prawdę, że się udało
|
// Aktualizujemy informację o pozycji w pionku
|
||||||
return true;
|
board[target.x][target.y]->setPosition(target);
|
||||||
}
|
|
||||||
|
|
||||||
bool Board::isMovementPossible(Movement movement)
|
// Zwracamy prawdę, że się udało
|
||||||
{
|
return true;
|
||||||
/** TODO **/
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pawn Board::deletePawn(Vector position)
|
Pawn Board::deletePawn(Vector position)
|
||||||
{
|
{
|
||||||
Pawn deleted_pawn = *board[position.x][position.y];
|
Pawn deleted_pawn = *board[position.x][position.y];
|
||||||
delete board[position.x][position.y];
|
delete board[position.x][position.y];
|
||||||
board[position.x][position.y] = NULL;
|
board[position.x][position.y] = NULL;
|
||||||
return deleted_pawn;
|
return deleted_pawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::draw(sf::RenderWindow& window)
|
void Board::draw(sf::RenderWindow& window)
|
||||||
{
|
{
|
||||||
// Wymiar X
|
// Wymiar X
|
||||||
for(int x=0; x<TILES_COUNT; ++x)
|
for(int x=0; x<TILES_COUNT; ++x)
|
||||||
{
|
|
||||||
// Wymiar Y
|
|
||||||
for(int y=0; y<TILES_COUNT; ++y)
|
|
||||||
{
|
{
|
||||||
// Tworzymy pojedynczy kafelek o wymiarach TILE_SIZE x TILE_SIZE
|
// Wymiar Y
|
||||||
sf::RectangleShape tile(sf::Vector2f(TILE_SIZE, TILE_SIZE));
|
for(int y=0; y<TILES_COUNT; ++y)
|
||||||
|
{
|
||||||
|
// Tworzymy pojedynczy kafelek o wymiarach TILE_SIZE x TILE_SIZE
|
||||||
|
sf::RectangleShape tile(sf::Vector2f(TILE_SIZE, TILE_SIZE));
|
||||||
|
|
||||||
// Ustawiamy pozycję na i*TILE_SIZE, j*TILE_SIZE -- czyli np. dla TILE_SIZE = 64: (0,0), (0,64), (0,128), ...
|
// Ustawiamy pozycję na i*TILE_SIZE, j*TILE_SIZE -- czyli np. dla TILE_SIZE = 64: (0,0), (0,64), (0,128), ...
|
||||||
tile.setPosition(x*TILE_SIZE, y*TILE_SIZE);
|
tile.setPosition(x*TILE_SIZE, y*TILE_SIZE);
|
||||||
|
|
||||||
// Ustawiamy kolor wypełnienia co drugiego kafelka na jasny
|
// Ustawiamy kolor wypełnienia co drugiego kafelka na jasny
|
||||||
tile.setFillColor(((x+y)%2)?sf::Color(150, 74, 0):sf::Color(248, 246, 184));
|
tile.setFillColor(((x+y)%2)?sf::Color(150, 74, 0):sf::Color(248, 246, 184));
|
||||||
|
|
||||||
// Rysujemy kafelki
|
// Rysujemy kafelki
|
||||||
window.draw(tile);
|
window.draw(tile);
|
||||||
|
|
||||||
// Jeżeli istnieją na danym polu pionki, to je rysujemy
|
// Jeżeli istnieją na danym polu pionki, to je rysujemy
|
||||||
if(board[x][y]) board[x][y]->draw(window);
|
if(board[x][y]) board[x][y]->draw(window);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Zaznacz kafelki przeznaczone do zaznaczenia
|
|
||||||
for(auto selected_tile: selected_tiles)
|
|
||||||
{
|
|
||||||
// Pobieramy współrzędne
|
|
||||||
int x = selected_tile.x;
|
|
||||||
int y = selected_tile.y;
|
|
||||||
|
|
||||||
// Tworzymy pojedynczy kafelek o wymiarach TILE_SIZE x TILE_SIZE
|
|
||||||
sf::RectangleShape tile(sf::Vector2f(TILE_SIZE, TILE_SIZE));
|
|
||||||
|
|
||||||
// Ustawiamy pozycję na i*TILE_SIZE, j*TILE_SIZE -- czyli np. dla TILE_SIZE = 64: (0,0), (0,64), (0,128), ...
|
// Zaznacz kafelki przeznaczone do zaznaczenia
|
||||||
tile.setPosition(x*TILE_SIZE, y*TILE_SIZE);
|
for(auto selected_tile: selected_tiles)
|
||||||
|
{
|
||||||
|
// Pobieramy współrzędne
|
||||||
|
int x = selected_tile.x;
|
||||||
|
int y = selected_tile.y;
|
||||||
|
|
||||||
// Ustawiamy kolor wypełnienia co drugiego kafelka na jasny
|
// Tworzymy pojedynczy kafelek o wymiarach TILE_SIZE x TILE_SIZE
|
||||||
tile.setFillColor(((x+y)%2)?sf::Color(200, 124, 50):sf::Color(255, 255, 220));
|
sf::RectangleShape tile(sf::Vector2f(TILE_SIZE, TILE_SIZE));
|
||||||
|
|
||||||
// Rysujemy kafelki
|
// Ustawiamy pozycję na i*TILE_SIZE, j*TILE_SIZE -- czyli np. dla TILE_SIZE = 64: (0,0), (0,64), (0,128), ...
|
||||||
window.draw(tile);
|
tile.setPosition(x*TILE_SIZE, y*TILE_SIZE);
|
||||||
|
|
||||||
// Jeżeli istnieją na danym polu pionki, to je rysujemy
|
// Jeżeli to zwykłe zaznaczenie, ustawiamy kolor wypełnienia co drugiego kafelka na jasny
|
||||||
if(board[x][y]) board[x][y]->draw(window);
|
if(!is_selected_movement)
|
||||||
}
|
tile.setFillColor(((x+y)%2)?sf::Color(200, 124, 50):sf::Color(255, 255, 220));
|
||||||
|
else
|
||||||
|
tile.setFillColor(((x+y)%2)?sf::Color(167, 200, 50):sf::Color(178, 255, 174));
|
||||||
|
|
||||||
|
// Rysujemy kafelki
|
||||||
|
window.draw(tile);
|
||||||
|
|
||||||
|
// Jeżeli istnieją na danym polu pionki, to je rysujemy
|
||||||
|
if(board[x][y]) board[x][y]->draw(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pawn* Board::selectPawn(Vector position)
|
Pawn* Board::selectPawn(Vector position)
|
||||||
{
|
{
|
||||||
// Jeżeli pionek na tym polu istnieje
|
// Jeżeli pionek na tym polu istnieje
|
||||||
if(board[position.x][position.y])
|
if(board[position.x][position.y])
|
||||||
{
|
{
|
||||||
// Odznaczamy wszystkie pionki
|
// Odznaczamy wszystkie pionki
|
||||||
for(int x = 0; x<TILES_COUNT; ++x)
|
for(int x = 0; x<TILES_COUNT; ++x)
|
||||||
for(int y = 0; y<TILES_COUNT; ++y)
|
for(int y = 0; y<TILES_COUNT; ++y)
|
||||||
if(board[x][y]) board[x][y]->deselect();
|
if(board[x][y]) board[x][y]->deselect();
|
||||||
|
|
||||||
// Zaznaczamy właściwy
|
// Zaznaczamy właściwy
|
||||||
board[position.x][position.y]->select();
|
board[position.x][position.y]->select();
|
||||||
|
|
||||||
// Zwracamy zaznaczony
|
// Zwracamy zaznaczony
|
||||||
return board[position.x][position.y];
|
return board[position.x][position.y];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zwracamy NULL, bo pionek nie istnieje
|
// Zwracamy NULL, bo pionek nie istnieje
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Board::isPossibleBeating(Vector position)
|
bool Board::isPossibleBeating(Vector position)
|
||||||
{
|
{
|
||||||
return getPossibleBeatings(position).size();
|
return getPossibleBeatings(position).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Board::arePossibleGlobalBeatings(Color color)
|
bool Board::arePossibleGlobalBeatings(Color color)
|
||||||
{
|
{
|
||||||
return getPossibleGlobalBeatings(color).size();
|
return getPossibleGlobalBeatings(color).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::list<Movement> Board::getPossibleBeatings(Vector position)
|
std::list<Movement> Board::getPossibleBeatings(Vector position)
|
||||||
{
|
{
|
||||||
// Tworzymy nowy kontener na pozycje
|
// Tworzymy nowy kontener na pozycje
|
||||||
std::list<Movement> beatings;
|
std::list<Movement> beatings;
|
||||||
|
|
||||||
// Pobieramy wskaźnik do pionka znajdującego się na zadanej pozycji
|
|
||||||
Pawn* position_pawn = getPawn(position);
|
|
||||||
|
|
||||||
// Jeżeli go tam nie ma, zwracamy pusty kontener
|
// Pobieramy wskaźnik do pionka znajdującego się na zadanej pozycji
|
||||||
if(!position_pawn) return beatings;
|
Pawn* position_pawn = getPawn(position);
|
||||||
|
|
||||||
//// Bicie normalnymi pionkami
|
// Jeżeli go tam nie ma, zwracamy pusty kontener
|
||||||
|
if(!position_pawn) return beatings;
|
||||||
|
|
||||||
// Bicie o wektor [-2, -2]
|
//// Bicie normalnymi pionkami
|
||||||
if((position.x >= 2 && position.y >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
|
||||||
(getPawn(position+Vector(-1, -1))) && // Jeżeli istnieje bity pionek
|
|
||||||
(getPawn(position+Vector(-1, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
|
||||||
(!getPawn(position+Vector(-2, -2)))) // Jeżeli pole docelowe jest puste
|
|
||||||
beatings.push_back(Movement(position, position+Vector(-2, -2))); // Dorzuć ruch do listy
|
|
||||||
|
|
||||||
// Bicie o wektor [-2, 2]
|
// Bicie o wektor [-2, -2]
|
||||||
if((position.x >= 2 && position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
if((position.x >= 2 && position.y >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
(getPawn(position+Vector(-1, 1))) && // Jeżeli istnieje bity pionek
|
(getPawn(position+Vector(-1, -1))) && // Jeżeli istnieje bity pionek
|
||||||
(getPawn(position+Vector(-1, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
(getPawn(position+Vector(-1, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
(!getPawn(position+Vector(-2, 2)))) // Jeżeli pole docelowe jest puste
|
(!getPawn(position+Vector(-2, -2)))) // Jeżeli pole docelowe jest puste
|
||||||
beatings.push_back(Movement(position, position+Vector(-2, 2))); // Dorzuć ruch do listy
|
beatings.push_back(Movement(position, position+Vector(-2, -2))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
// Bicie o wektor [2, 2]
|
// Bicie o wektor [-2, 2]
|
||||||
if((position.x < TILES_COUNT-2 && position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
if((position.x >= 2 && position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
(getPawn(position+Vector(1, 1))) && // Jeżeli istnieje bity pionek
|
(getPawn(position+Vector(-1, 1))) && // Jeżeli istnieje bity pionek
|
||||||
(getPawn(position+Vector(1, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
(getPawn(position+Vector(-1, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
(!getPawn(position+Vector(2, 2)))) // Jeżeli pole docelowe jest puste
|
(!getPawn(position+Vector(-2, 2)))) // Jeżeli pole docelowe jest puste
|
||||||
beatings.push_back(Movement(position, position+Vector(2, 2))); // Dorzuć ruch do listy
|
beatings.push_back(Movement(position, position+Vector(-2, 2))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
// Bicie o wektor [2, -2]
|
// Bicie o wektor [2, 2]
|
||||||
if((position.x < TILES_COUNT-2 && position.y >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
if((position.x < TILES_COUNT-2 && position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
(getPawn(position+Vector(1, -1))) && // Jeżeli istnieje bity pionek
|
(getPawn(position+Vector(1, 1))) && // Jeżeli istnieje bity pionek
|
||||||
(getPawn(position+Vector(1, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
(getPawn(position+Vector(1, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
(!getPawn(position+Vector(2, -2)))) // Jeżeli pole docelowe jest puste
|
(!getPawn(position+Vector(2, 2)))) // Jeżeli pole docelowe jest puste
|
||||||
beatings.push_back(Movement(position, position+Vector(2, -2))); // Dorzuć ruch do listy
|
beatings.push_back(Movement(position, position+Vector(2, 2))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
//// Bicie damkami
|
|
||||||
|
|
||||||
// Jeżeli pionek jest damką posiada dodatkowe możliwości bicia
|
|
||||||
if(getPawn(position)->isQueen())
|
|
||||||
{
|
|
||||||
// Bicie o wektor [-2, 0]
|
|
||||||
if((position.x >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
|
||||||
(getPawn(position+Vector(-1, 0))) && // Jeżeli istnieje bity pionek
|
|
||||||
(getPawn(position+Vector(-1, 0))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
|
||||||
(!getPawn(position+Vector(-2, 0)))) // Jeżeli pole docelowe jest puste
|
|
||||||
beatings.push_back(Movement(position, position+Vector(-2, 0))); // Dorzuć ruch do listy
|
|
||||||
|
|
||||||
// Bicie o wektor [0, 2]
|
// Bicie o wektor [2, -2]
|
||||||
if((position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
if((position.x < TILES_COUNT-2 && position.y >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
(getPawn(position+Vector(0, 1))) && // Jeżeli istnieje bity pionek
|
(getPawn(position+Vector(1, -1))) && // Jeżeli istnieje bity pionek
|
||||||
(getPawn(position+Vector(0, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
(getPawn(position+Vector(1, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
(!getPawn(position+Vector(0, 2)))) // Jeżeli pole docelowe jest puste
|
(!getPawn(position+Vector(2, -2)))) // Jeżeli pole docelowe jest puste
|
||||||
beatings.push_back(Movement(position, position+Vector(0, 2))); // Dorzuć ruch do listy
|
beatings.push_back(Movement(position, position+Vector(2, -2))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
// Bicie o wektor [2, 0]
|
//// Bicie damkami
|
||||||
if((position.x < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
|
||||||
(getPawn(position+Vector(1, 0))) && // Jeżeli istnieje bity pionek
|
|
||||||
(getPawn(position+Vector(1, 0))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
|
||||||
(!getPawn(position+Vector(2, 0)))) // Jeżeli pole docelowe jest puste
|
|
||||||
beatings.push_back(Movement(position, position+Vector(2, 0))); // Dorzuć ruch do listy
|
|
||||||
|
|
||||||
// Bicie o wektor [0, -2]
|
// Jeżeli pionek jest damką posiada dodatkowe możliwości bicia
|
||||||
if((position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
if(getPawn(position)->isQueen())
|
||||||
(getPawn(position+Vector(0, -1))) && // Jeżeli istnieje bity pionek
|
{
|
||||||
(getPawn(position+Vector(0, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
// Bicie o wektor [-2, 0]
|
||||||
(!getPawn(position+Vector(0, -2)))) // Jeżeli pole docelowe jest puste
|
if((position.x >= 2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
beatings.push_back(Movement(position, position+Vector(0, -2))); // Dorzuć ruch do listy
|
(getPawn(position+Vector(-1, 0))) && // Jeżeli istnieje bity pionek
|
||||||
}
|
(getPawn(position+Vector(-1, 0))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
|
(!getPawn(position+Vector(-2, 0)))) // Jeżeli pole docelowe jest puste
|
||||||
|
beatings.push_back(Movement(position, position+Vector(-2, 0))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
|
// Bicie o wektor [0, 2]
|
||||||
|
if((position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
|
(getPawn(position+Vector(0, 1))) && // Jeżeli istnieje bity pionek
|
||||||
|
(getPawn(position+Vector(0, 1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
|
(!getPawn(position+Vector(0, 2)))) // Jeżeli pole docelowe jest puste
|
||||||
|
beatings.push_back(Movement(position, position+Vector(0, 2))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
|
// Bicie o wektor [2, 0]
|
||||||
|
if((position.x < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
|
(getPawn(position+Vector(1, 0))) && // Jeżeli istnieje bity pionek
|
||||||
|
(getPawn(position+Vector(1, 0))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
|
(!getPawn(position+Vector(2, 0)))) // Jeżeli pole docelowe jest puste
|
||||||
|
beatings.push_back(Movement(position, position+Vector(2, 0))); // Dorzuć ruch do listy
|
||||||
|
|
||||||
|
// Bicie o wektor [0, -2]
|
||||||
|
if((position.y < TILES_COUNT-2) && // Jeżeli bicie nie wyjdzie poza planszę
|
||||||
|
(getPawn(position+Vector(0, -1))) && // Jeżeli istnieje bity pionek
|
||||||
|
(getPawn(position+Vector(0, -1))->getColor() != position_pawn->getColor()) && // Jeżeli jest to pionek przeciwnego koloru
|
||||||
|
(!getPawn(position+Vector(0, -2)))) // Jeżeli pole docelowe jest puste
|
||||||
|
beatings.push_back(Movement(position, position+Vector(0, -2))); // Dorzuć ruch do listy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zwracamy kontener
|
||||||
|
return beatings;
|
||||||
|
|
||||||
// Zwracamy kontener
|
|
||||||
return beatings;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Movement> Board::getPossibleMovements(Vector position)
|
std::list<Movement> Board::getPossibleMovements(Vector position)
|
||||||
{
|
{
|
||||||
// Jeżeli są możliwe bicia, zwróć je
|
// Jeżeli są możliwe bicia, zwróć je
|
||||||
if(isPossibleBeating(position)) return getPossibleBeatings(position);
|
if(isPossibleBeating(position)) return getPossibleBeatings(position);
|
||||||
|
|
||||||
std::list<Movement> movements;
|
std::list<Movement> movements;
|
||||||
|
|
||||||
// Jeżeli pionek nie istnieje, zwróć pustą listę
|
|
||||||
if(!getPawn(position)) return movements;
|
|
||||||
|
|
||||||
// Jeżeli pionek jest damką
|
|
||||||
if(getPawn(position)->isQueen())
|
|
||||||
{
|
|
||||||
|
|
||||||
// Jeżeli ruch w górę-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
// Jeżeli pionek nie istnieje, zwróć pustą listę
|
||||||
if(position.x >= 1 && position.y >= 1)
|
if(!getPawn(position)) return movements;
|
||||||
if(!getPawn(position+Vector(-1, -1))) movements.push_back(Movement(position, position+Vector(-1, -1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w górę-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.x < TILES_COUNT-1 && position.y >= 1)
|
|
||||||
if(!getPawn(position+Vector(1, -1))) movements.push_back(Movement(position, position+Vector(1, -1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w dół-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
// Jeżeli pionek jest damką
|
||||||
if(position.x >= 1 && position.y < TILES_COUNT-1)
|
if(getPawn(position)->isQueen())
|
||||||
if(!getPawn(position+Vector(-1, 1))) movements.push_back(Movement(position, position+Vector(-1, 1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w dół-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.x < TILES_COUNT-1 && position.y < TILES_COUNT-1)
|
|
||||||
if(!getPawn(position+Vector(1, 1))) movements.push_back(Movement(position, position+Vector(1, 1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w górę jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.y >= 1)
|
|
||||||
if(!getPawn(position+Vector(0, -1))) movements.push_back(Movement(position, position+Vector(0, -1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w dół jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.y < TILES_COUNT-1)
|
|
||||||
if(!getPawn(position+Vector(0, 1))) movements.push_back(Movement(position, position+Vector(0, 1)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.x >= 1)
|
|
||||||
if(!getPawn(position+Vector(-1, 0))) movements.push_back(Movement(position, position+Vector(-1, 0)));
|
|
||||||
|
|
||||||
// Jeżeli ruch w prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
|
||||||
if(position.x < TILES_COUNT-1)
|
|
||||||
if(!getPawn(position+Vector(1, 0))) movements.push_back(Movement(position, position+Vector(1, 0)));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jeżeli jest to zwykły pionek
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Jeżeli to ruch białego pionka
|
|
||||||
if(getPawn(position)->getColor() == CL_WHITE)
|
|
||||||
{
|
{
|
||||||
// Jeżeli ruch w górę-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
// Jeżeli ruch w górę-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
if(position.x >= 1 && position.y >= 1)
|
if(position.x >= 1 && position.y >= 1)
|
||||||
if(!getPawn(position+Vector(-1, -1))) movements.push_back(Movement(position, position+Vector(-1, -1)));
|
if(!getPawn(position+Vector(-1, -1))) movements.push_back(Movement(position, position+Vector(-1, -1)));
|
||||||
|
|
||||||
// Jeżeli ruch w górę-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
// Jeżeli ruch w górę-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
if(position.x < TILES_COUNT-1 && position.y >= 1)
|
if(position.x < TILES_COUNT-1 && position.y >= 1)
|
||||||
if(!getPawn(position+Vector(1, -1))) movements.push_back(Movement(position, position+Vector(1, -1)));
|
if(!getPawn(position+Vector(1, -1))) movements.push_back(Movement(position, position+Vector(1, -1)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w dół-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x >= 1 && position.y < TILES_COUNT-1)
|
||||||
|
if(!getPawn(position+Vector(-1, 1))) movements.push_back(Movement(position, position+Vector(-1, 1)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w dół-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x < TILES_COUNT-1 && position.y < TILES_COUNT-1)
|
||||||
|
if(!getPawn(position+Vector(1, 1))) movements.push_back(Movement(position, position+Vector(1, 1)));
|
||||||
|
|
||||||
|
// TODO zmodyfikowane ruchy
|
||||||
|
// TODO - zrobić, aby damka mogła robić długie ruchy (to samo dla bicia!)
|
||||||
|
|
||||||
|
// Jeżeli ruch w górę jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.y >= 1)
|
||||||
|
;//if(!getPawn(position+Vector(0, -1))) movements.push_back(Movement(position, position+Vector(0, -1)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w dół jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.y < TILES_COUNT-1)
|
||||||
|
;//if(!getPawn(position+Vector(0, 1))) movements.push_back(Movement(position, position+Vector(0, 1)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x >= 1)
|
||||||
|
;//if(!getPawn(position+Vector(-1, 0))) movements.push_back(Movement(position, position+Vector(-1, 0)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x < TILES_COUNT-1)
|
||||||
|
;//if(!getPawn(position+Vector(1, 0))) movements.push_back(Movement(position, position+Vector(1, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jeżeli to ruch czarnego pionka
|
// Jeżeli jest to zwykły pionek
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Jeżeli ruch w dół-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
// Jeżeli to ruch białego pionka
|
||||||
if(position.x >= 1 && position.y < TILES_COUNT-1)
|
if(getPawn(position)->getColor() == CL_WHITE)
|
||||||
if(!getPawn(position+Vector(-1, 1))) movements.push_back(Movement(position, position+Vector(-1, 1)));
|
{
|
||||||
|
// Jeżeli ruch w górę-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
// Jeżeli ruch w dół-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
if(position.x >= 1 && position.y >= 1)
|
||||||
if(position.x < TILES_COUNT-1 && position.y < TILES_COUNT-1)
|
if(!getPawn(position+Vector(-1, -1))) movements.push_back(Movement(position, position+Vector(-1, -1)));
|
||||||
if(!getPawn(position+Vector(1, 1))) movements.push_back(Movement(position, position+Vector(1, 1)));
|
|
||||||
|
// Jeżeli ruch w górę-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x < TILES_COUNT-1 && position.y >= 1)
|
||||||
|
if(!getPawn(position+Vector(1, -1))) movements.push_back(Movement(position, position+Vector(1, -1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jeżeli to ruch czarnego pionka
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Jeżeli ruch w dół-lewo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x >= 1 && position.y < TILES_COUNT-1)
|
||||||
|
if(!getPawn(position+Vector(-1, 1))) movements.push_back(Movement(position, position+Vector(-1, 1)));
|
||||||
|
|
||||||
|
// Jeżeli ruch w dół-prawo jest możliwy (jest puste miejsce) dorzuć ruch do listy
|
||||||
|
if(position.x < TILES_COUNT-1 && position.y < TILES_COUNT-1)
|
||||||
|
if(!getPawn(position+Vector(1, 1))) movements.push_back(Movement(position, position+Vector(1, 1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return movements;
|
||||||
return movements;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Movement> Board::getPossibleGlobalBeatings(Color color)
|
std::list<Movement> Board::getPossibleGlobalBeatings(Color color)
|
||||||
{
|
{
|
||||||
std::list<Movement> movements;
|
std::list<Movement> movements;
|
||||||
|
|
||||||
// Dla każdych pionków
|
// Dla każdych pionków
|
||||||
for(int x = 0; x < TILES_COUNT; ++x)
|
for(int x = 0; x < TILES_COUNT; ++x)
|
||||||
for(int y = 0; y < TILES_COUNT; ++y)
|
for(int y = 0; y < TILES_COUNT; ++y)
|
||||||
{
|
{
|
||||||
// Jeżeli to jest pionek
|
// Jeżeli to jest pionek
|
||||||
if(board[x][y])
|
if(board[x][y])
|
||||||
{
|
{
|
||||||
// Jeżeli jest to pionek o który nam chodzi
|
// Jeżeli jest to pionek o który nam chodzi
|
||||||
if(board[x][y]->getColor() == color)
|
if(board[x][y]->getColor() == color)
|
||||||
|
|
||||||
// Dodaj wszystkie jego możliwe ruchy do listy ruchów
|
// Dodaj wszystkie jego możliwe ruchy do listy ruchów
|
||||||
for(auto m: getPossibleBeatings(Vector(x, y))) movements.push_back(m);
|
for(auto m: getPossibleBeatings(Vector(x, y))) movements.push_back(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return movements;
|
return movements;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Movement> Board::getPossibleGlobalMovements(Color color)
|
std::list<Movement> Board::getPossibleGlobalMovements(Color color)
|
||||||
{
|
{
|
||||||
std::list<Movement> movements;
|
std::list<Movement> movements;
|
||||||
|
|
||||||
// Jeżeli istnieją bicia zwracamy tylko je
|
// Jeżeli istnieją bicia zwracamy tylko je
|
||||||
if(arePossibleGlobalBeatings(color)) return getPossibleGlobalBeatings(color);
|
if(arePossibleGlobalBeatings(color)) return getPossibleGlobalBeatings(color);
|
||||||
|
|
||||||
// Dla każdych pionków
|
|
||||||
for(int x = 0; x < TILES_COUNT; ++x)
|
|
||||||
for(int y = 0; y < TILES_COUNT; ++y)
|
|
||||||
{
|
|
||||||
// Jeżeli to jest pionek
|
|
||||||
if(board[x][y])
|
|
||||||
{
|
|
||||||
// Jeżeli jest to pionek o który nam chodzi
|
|
||||||
if(board[x][y]->getColor() == color)
|
|
||||||
|
|
||||||
// Dodaj wszystkie jego możliwe ruchy do listy ruchów
|
// Dla każdych pionków
|
||||||
for(auto m: getPossibleMovements(Vector(x, y))) movements.push_back(m);
|
for(int x = 0; x < TILES_COUNT; ++x)
|
||||||
}
|
for(int y = 0; y < TILES_COUNT; ++y)
|
||||||
}
|
{
|
||||||
|
// Jeżeli to jest pionek
|
||||||
return movements;
|
if(board[x][y])
|
||||||
|
{
|
||||||
|
// Jeżeli jest to pionek o który nam chodzi
|
||||||
|
if(board[x][y]->getColor() == color)
|
||||||
|
|
||||||
|
// Dodaj wszystkie jego możliwe ruchy do listy ruchów
|
||||||
|
for(auto m: getPossibleMovements(Vector(x, y))) movements.push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return movements;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::display()
|
void Board::display()
|
||||||
{
|
{
|
||||||
// Wyświetl poziomą linię
|
// Wyświetl poziomą linię
|
||||||
for(int i=0; i<TILES_COUNT; ++i) std::cout << "+---";
|
for(int i=0; i<TILES_COUNT; ++i) std::cout << "+---";
|
||||||
std::cout << "+" << std::endl;
|
std::cout << "+" << std::endl;
|
||||||
|
|
||||||
// Wyświetl całą planszę
|
// Wyświetl całą planszę
|
||||||
for(int y = 0; y<TILES_COUNT; ++y)
|
for(int y = 0; y<TILES_COUNT; ++y)
|
||||||
{
|
|
||||||
// Pojedynczy wiersz
|
|
||||||
for(int x = 0; x<TILES_COUNT; ++x)
|
|
||||||
{
|
{
|
||||||
std::cout << "|";
|
// Pojedynczy wiersz
|
||||||
if(board[x][y])
|
for(int x = 0; x<TILES_COUNT; ++x)
|
||||||
{
|
{
|
||||||
if(board[x][y]->getColor() == CL_WHITE) std::cout << " O ";
|
std::cout << "|";
|
||||||
else std::cout << " @ ";
|
if(board[x][y])
|
||||||
} else std::cout << " ";
|
{
|
||||||
}
|
if(board[x][y]->getColor() == CL_WHITE) std::cout << " O ";
|
||||||
std::cout << "|" << std::endl;
|
else std::cout << " @ ";
|
||||||
|
} else std::cout << " ";
|
||||||
|
}
|
||||||
|
std::cout << "|" << std::endl;
|
||||||
|
|
||||||
// Pozioma linia
|
// Pozioma linia
|
||||||
for(int i=0; i<TILES_COUNT; ++i) std::cout << "+---";
|
for(int i=0; i<TILES_COUNT; ++i) std::cout << "+---";
|
||||||
std::cout << "+" << std::endl;
|
std::cout << "+" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Board::Board(const Board& original)
|
Board::Board(const Board& original)
|
||||||
{
|
{
|
||||||
// Czyścimy całą tablicę
|
// Czyścimy całą tablicę
|
||||||
for(int i=0; i<TILES_COUNT; ++i) for(int j=0; j<TILES_COUNT; ++j) board[i][j] = NULL;
|
for(int i=0; i<TILES_COUNT; ++i) for(int j=0; j<TILES_COUNT; ++j) board[i][j] = NULL;
|
||||||
|
|
||||||
// Kopiujemy wszystko...
|
// Kopiujemy wszystko...
|
||||||
for(int x = 0; x<TILES_COUNT; ++x)
|
for(int x = 0; x<TILES_COUNT; ++x)
|
||||||
for(int y = 0; y<TILES_COUNT; ++y)
|
for(int y = 0; y<TILES_COUNT; ++y)
|
||||||
|
{
|
||||||
|
// Jeżeli istnieje pionek na tym polu...
|
||||||
|
if(original.board[x][y])
|
||||||
|
{
|
||||||
|
// ... to w nowotworzonej planszy tworzymy identyczny pionek
|
||||||
|
createPawn(Vector(x, y), original.board[x][y]->getColor());
|
||||||
|
|
||||||
// Jeżeli istnieje pionek na tym polu...
|
// Jeżeli ten pionek jest damką ...
|
||||||
if(original.board[x][y])
|
if(original.board[x][y]->isQueen())
|
||||||
|
|
||||||
|
// ... to promujemy nowoutworzonego pionka na damkę
|
||||||
|
board[x][y]->upgrade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ... to w nowotworzonej planszy tworzymy identyczny pionek
|
}
|
||||||
createPawn(Vector(x, y), original.board[x][y]->getColor());
|
|
||||||
|
unsigned int Board::getNumberOfWhitePawns() const
|
||||||
|
{
|
||||||
|
// Inicjujemy licznik
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
// Przeglądamy calą planszę
|
||||||
|
for(int x = 0; x < TILES_COUNT; ++x)
|
||||||
|
for(int y = 0; y < TILES_COUNT; ++y)
|
||||||
|
|
||||||
|
// Jeśli znajdziemy biały pionek, zwiększamy licznik o 1
|
||||||
|
if(board[x][y] && board[x][y]->getColor() == CL_WHITE) ++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Board::getNumberOfBlackPawns() const
|
||||||
|
{
|
||||||
|
// Inicjujemy licznik
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
// Przeglądamy calą planszę
|
||||||
|
for(int x = 0; x < TILES_COUNT; ++x)
|
||||||
|
for(int y = 0; y < TILES_COUNT; ++y)
|
||||||
|
|
||||||
|
// Jeśli znajdziemy czarny pionek, zwiększamy licznik o 1
|
||||||
|
if(board[x][y] && board[x][y]->getColor() == CL_BLACK) ++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::upgrade()
|
||||||
|
{
|
||||||
|
// Dla całej szerokości planszy (czyli całej linii)
|
||||||
|
for(int x = 0; x < TILES_COUNT; ++x)
|
||||||
|
{
|
||||||
|
// Jeśli na górnej linii promocji znajduje się biały pionek, promuj go
|
||||||
|
if(board[x][0] && board[x][0]->getColor() == CL_WHITE) board[x][0]->upgrade();
|
||||||
|
|
||||||
|
// Jeśli na dolnej linii promocji znajduje się czarny pionek, promuj go
|
||||||
|
if(board[x][TILES_COUNT-1] && board[x][TILES_COUNT-1]->getColor() == CL_BLACK) board[x][TILES_COUNT-1]->upgrade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Board::selectMovement(Movement movement)
|
||||||
|
{
|
||||||
|
is_selected_movement = true;
|
||||||
|
selected_tiles.push_back(movement.begin);
|
||||||
|
selected_tiles.push_back(movement.end);
|
||||||
}
|
}
|
||||||
|
|||||||
446
src/game.cpp
446
src/game.cpp
@@ -1,289 +1,269 @@
|
|||||||
#include "../inc/game.hh"
|
#include "../inc/game.hh"
|
||||||
|
|
||||||
Game::Game()
|
Game::Game(Color player, int ai)
|
||||||
:
|
:
|
||||||
selected(TILES_COUNT+1, TILES_COUNT+1), // Brak zaznaczenia
|
game_state(GS_RUNNING), // Stan gry
|
||||||
player_color(CL_WHITE), // Domyślny kolor gracza
|
selected(TILES_COUNT+1, TILES_COUNT+1), // Brak zaznaczenia
|
||||||
round(CL_WHITE), // Pierwszy ruch mają białe pionki
|
player_color(player), // Kolor gracza
|
||||||
movements_sequence(false), // Ciąg kolejnych ruchów
|
round(CL_WHITE), // Pierwszy ruch mają białe pionki
|
||||||
player_score(0), // Wyzerowana ilość punktów gracza
|
player_score(0), // Wyzerowana ilość punktów gracza
|
||||||
ai_score(0), // Wyzerowana ilość punktów AI
|
ai_score(0), // Wyzerowana ilość punktów AI
|
||||||
minimax(7, getAIColor()) // Poziom AI oraz kolor AI
|
minimax(ai, getAIColor()) // Poziom AI oraz kolor AI
|
||||||
{
|
|
||||||
// Ustawienia antyaliasingu
|
|
||||||
sf::ContextSettings settings;
|
|
||||||
settings.antialiasingLevel = 8;
|
|
||||||
|
|
||||||
// Utworzenie okna
|
|
||||||
window.create(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32), GAME_TITLE, sf::Style::Close, settings);
|
|
||||||
|
|
||||||
// Wygenerowanie planszy startowej
|
{
|
||||||
board.initBoard();
|
// Ustawienia antyaliasingu
|
||||||
|
sf::ContextSettings settings;
|
||||||
// Pętla główna
|
settings.antialiasingLevel = 8;
|
||||||
loop();
|
|
||||||
|
// Utworzenie okna
|
||||||
|
window.create(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32), GAME_TITLE, sf::Style::Close, settings);
|
||||||
|
|
||||||
|
// Wygenerowanie planszy startowej
|
||||||
|
board.initBoard();
|
||||||
|
|
||||||
|
// Pętla główna
|
||||||
|
loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::killPawn(Vector position)
|
void Game::killPawn(Vector position)
|
||||||
{
|
{
|
||||||
// Dodaj odpowiednio punkty
|
// Dodaj odpowiednio punkty
|
||||||
if(board.getPawn(position)->getColor() == getPlayerColor()) ++ai_score;
|
if(board.getPawn(position)->getColor() == getPlayerColor()) ++ai_score;
|
||||||
else ++player_score;
|
else ++player_score;
|
||||||
|
|
||||||
// Usuń pionek
|
// Usuń pionek
|
||||||
board.deletePawn(position);
|
board.deletePawn(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player Game::getPlayer(Vector position)
|
Player Game::getPlayer(Vector position)
|
||||||
{
|
{
|
||||||
if(board.getPawn(position)->getColor() == getPlayerColor()) return PL_HUMAN;
|
if(board.getPawn(position)->getColor() == getPlayerColor()) return PL_HUMAN;
|
||||||
else return PL_AI;
|
else return PL_AI;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::movePawn(Movement movement)
|
bool Game::movePawn(Movement movement)
|
||||||
{
|
{
|
||||||
// Pomocnicze wektory
|
// Lista możliwych ruchów
|
||||||
Vector& position = movement.begin;
|
std::list<Movement> possible_movements = board.getPossibleGlobalMovements(round);
|
||||||
Vector& target = movement.end;
|
|
||||||
|
|
||||||
// Jeżeli pionek startowy nie istnieje
|
|
||||||
if(!board.getPawn(position)) return false;
|
|
||||||
|
|
||||||
// Jeżeli ruch należy do drugiego gracza
|
|
||||||
if(board.getPawn(position)->getColor() != round) return false;
|
|
||||||
|
|
||||||
// Jeżeli kafelek jest zajęty
|
|
||||||
if(board.getPawn(target)) return false;
|
|
||||||
|
|
||||||
// Jeżeli to ruch czarnego pionka
|
// Jeżeli ruch jest niemożliwy, zwróć false
|
||||||
if(board.getPawn(position)->getColor() == CL_BLACK)
|
if(find(possible_movements.begin(), possible_movements.end(), movement) == possible_movements.end()) return false;
|
||||||
{
|
|
||||||
// Jeżeli jest to zwykły ruch na ukos
|
|
||||||
if((target-position == Vector(1, 1)) || // Jeżeli jest to ruch o wektor [1, 1]
|
|
||||||
(target-position == Vector(-1, 1))) // --//--
|
|
||||||
return board.movePawn(Movement(position, target)); // Rusz pionek
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jeżeli to ruch białego pionka
|
// Jeżeli jest to bicie
|
||||||
if(board.getPawn(position)->getColor() == CL_WHITE)
|
if((movement.getVector() == Vector(-2, -2)) || // Możliwości bicia zwykłego pionka
|
||||||
{
|
(movement.getVector() == Vector(-2, 2)) ||
|
||||||
// Jeżeli jest to zwykły ruch na ukos
|
(movement.getVector() == Vector(2, -2)) ||
|
||||||
if((target-position == Vector(-1, -1)) || // Jeżeli jest to ruch o wektor [1, 1]
|
(movement.getVector() == Vector(2, 2)) ||
|
||||||
(target-position == Vector(1, -1))) // --//--
|
(movement.getVector() == Vector(-2, 0)) || // + możliwości bicia damką
|
||||||
return board.movePawn(Movement(position, target)); // Rusz pionek
|
(movement.getVector() == Vector(0, 2)) ||
|
||||||
}
|
(movement.getVector() == Vector(2, 0)) ||
|
||||||
|
(movement.getVector() == Vector(0, -2)))
|
||||||
// Jeżeli jest to przeskok nad drugim graczem
|
killPawn(movement.begin + movement.getVector()/2); // zbij zabijanego pionka
|
||||||
if((target-position == Vector(-2, -2)) && // Jeżeli jest to ruch o wektor [-2, -2]
|
|
||||||
(board.getPawn(position+Vector(-1, -1))) && // Jeżeli istnieje pionek na polu przesuniętym o [-1, -1]
|
|
||||||
(board.getPawn(position+Vector(-1, -1))->getColor() != board.getPawn(position)->getColor())) // Jeżeli jest to gracz o innym kolorze
|
|
||||||
{
|
|
||||||
// Zabij zbijanego pionka
|
|
||||||
killPawn(position+Vector(-1, -1));
|
|
||||||
|
|
||||||
// Przesuń pionek
|
// Wykonaj ruch i zwróć sukces, jeśli się powiodło
|
||||||
return board.movePawn(Movement(position, target));
|
return board.movePawn(movement);
|
||||||
}
|
|
||||||
|
|
||||||
if((target-position == Vector(-2, 2)) && // Jeżeli jest to ruch o wektor [-2, -2]
|
|
||||||
(board.getPawn(position+Vector(-1, 1))) && // Jeżeli istnieje pionek na polu przesuniętym o [-1, -1]
|
|
||||||
(board.getPawn(position+Vector(-1, 1))->getColor() != board.getPawn(position)->getColor())) // Jeżeli jest to gracz o innym kolorze
|
|
||||||
{
|
|
||||||
// Zabij zbijanego pionka
|
|
||||||
killPawn(position+Vector(-1, 1));
|
|
||||||
|
|
||||||
// Przesuń pionek
|
|
||||||
return board.movePawn(Movement(position, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((target-position == Vector(2, -2)) && // Jeżeli jest to ruch o wektor [-2, -2]
|
|
||||||
(board.getPawn(position+Vector(1, -1))) && // Jeżeli istnieje pionek na polu przesuniętym o [-1, -1]
|
|
||||||
(board.getPawn(position+Vector(1, -1))->getColor() != board.getPawn(position)->getColor())) // Jeżeli jest to gracz o innym kolorze
|
|
||||||
{
|
|
||||||
// Zabij zbijanego pionka
|
|
||||||
killPawn(position+Vector(1, -1));
|
|
||||||
|
|
||||||
// Przesuń pionek
|
|
||||||
return board.movePawn(Movement(position, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((target-position == Vector(2, 2)) && // Jeżeli jest to ruch o wektor [-2, -2]
|
|
||||||
(board.getPawn(position+Vector(1, 1))) && // Jeżeli istnieje pionek na polu przesuniętym o [-1, -1]
|
|
||||||
(board.getPawn(position+Vector(1, 1))->getColor() != board.getPawn(position)->getColor())) // Jeżeli jest to gracz o innym kolorze
|
|
||||||
{
|
|
||||||
// Zabij zbijanego pionka
|
|
||||||
killPawn(position+Vector(1, 1));
|
|
||||||
|
|
||||||
// Przesuń pionek
|
|
||||||
return board.movePawn(Movement(position, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::executePlayerRound(sf::Vector2f mouse_position)
|
void Game::executePlayerRound(sf::Vector2f mouse_position)
|
||||||
{
|
{
|
||||||
// Konwersja pozycji myszy na współrzędne kafelka
|
// Konwersja pozycji myszy na współrzędne kafelka
|
||||||
Vector position(mouse_position);
|
Vector position(mouse_position);
|
||||||
|
|
||||||
// Pobieramy informacje o pionku(lub jego braku) z interesującego nas pola
|
// Pobieramy informacje o pionku(lub jego braku) z interesującego nas pola
|
||||||
Pawn* ptr = board.getPawn(position);
|
Pawn* ptr = board.getPawn(position);
|
||||||
|
|
||||||
// Jeżeli tura należy do gracza, pionek istnieje i należy do gracza
|
// Jeżeli tura należy do gracza, pionek istnieje i należy do gracza
|
||||||
if((round == getPlayerColor()) && ptr && (ptr->getColor() == getPlayerColor()))
|
if((round == getPlayerColor()) && ptr && (ptr->getColor() == getPlayerColor()))
|
||||||
{
|
|
||||||
// Zaznaczamy pionek i pobieramy do niego wskaźnik
|
|
||||||
ptr = board.selectPawn(Vector(position));
|
|
||||||
|
|
||||||
// Pobieramy jego pozycję i zapisujemy do zmiennej przechowującej zaznaczony pionek
|
|
||||||
selected = ptr->getPosition();
|
|
||||||
|
|
||||||
// Zaznacz dozwolone kafelki na mapie
|
|
||||||
std::list<Vector> possible_tiles; // Lista dozwolonych kafelków
|
|
||||||
for(const auto& m: board.getPossibleMovements(selected)) // Pobieramy dozwolone kafelki docelowe z dozwolonych ruchów
|
|
||||||
possible_tiles.push_back(m.end);
|
|
||||||
board.selectTiles(possible_tiles); // Zaznaczamy je na planszy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jeżeli pionek nie istnieje w danym miejscu (czyli kliknięto na puste pole),
|
|
||||||
// to znaczy, że jest to ruch docelowy (czyli należy pionek przesunąć):
|
|
||||||
if(!ptr)
|
|
||||||
{
|
|
||||||
// Jeżeli pionek jest poprawnie zaznaczony
|
|
||||||
if(board.getPawn(selected))
|
|
||||||
{
|
{
|
||||||
// Pomocnicza flaga
|
// Odznaczamy wszystkie zaznaczenia
|
||||||
bool move_is_possible = false;
|
board.deselectTiles();
|
||||||
|
|
||||||
// Jeżeli możliwe jest bicie
|
|
||||||
if(board.isPossibleBeating(selected))
|
|
||||||
{
|
|
||||||
// Pobieramy listę możliwych bić
|
|
||||||
std::list<Movement> beatings = board.getPossibleBeatings(selected);
|
|
||||||
|
|
||||||
// Jeżeli gracz próbuje bić, zezwól na ruch (czyli bicie jest obowiązkowe)
|
// Zaznaczamy pionek i pobieramy do niego wskaźnik
|
||||||
if(find(beatings.begin(), beatings.end(), Movement(selected, position)) != beatings.end()) move_is_possible = true;
|
ptr = board.selectPawn(Vector(position));
|
||||||
}
|
|
||||||
|
|
||||||
// Jeżeli nie jest możliwe bicie, to zezwól na ruch
|
// Pobieramy jego pozycję i zapisujemy do zmiennej przechowującej zaznaczony pionek
|
||||||
else move_is_possible = true;
|
selected = ptr->getPosition();
|
||||||
|
|
||||||
// Jeżeli zezwolono na ruch
|
// Jeżeli nie ma możliwości bicia, zaznacz dozwolone kafelki na mapie
|
||||||
// przesuwamy pionek o ile to możliwe (kliknięte miejsce = position jest naszym docelowym kafelkiem)
|
if(!board.arePossibleGlobalBeatings(getPlayerColor()))
|
||||||
if(move_is_possible && movePawn(Movement(selected, position)))
|
|
||||||
{
|
|
||||||
// Ustaw sekwencję ruchów
|
|
||||||
movements_sequence = true;
|
|
||||||
|
|
||||||
// Jeżeli się udało, to aktualizujemy pozycję zaznaczonego pionka
|
|
||||||
selected = position;
|
|
||||||
|
|
||||||
// Jeżeli już nie ma możliwości bicia (bicie obowiązkowe), kończymy turę
|
|
||||||
if(!board.isPossibleBeating(selected))
|
|
||||||
{
|
{
|
||||||
// Kończymy sekwencję ruchów
|
std::list<Vector> possible_tiles; // Lista dozwolonych kafelków
|
||||||
movements_sequence = false;
|
for(const auto& m: board.getPossibleMovements(selected)) // Pobieramy dozwolone kafelki docelowe z dozwolonych ruchów
|
||||||
|
possible_tiles.push_back(m.end);
|
||||||
// Odznaczamy pionek
|
board.selectTiles(possible_tiles); // Zaznaczamy je na planszy
|
||||||
board.getPawn(selected)->deselect();
|
|
||||||
|
|
||||||
// Odznaczamy kafelki (EXPERIMENTAL)
|
|
||||||
board.deselectTiles();
|
|
||||||
|
|
||||||
// i kończymy turę
|
|
||||||
round = getAIColor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// W przeciwnym razie zaznaczamy na mapie dozwolone kafelki
|
// W przeciwnym wypadku zaznacz tylko bicia
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
board.deselectTiles();
|
std::list<Vector> possible_tiles; // Lista dozwolonych kafelków
|
||||||
std::list<Vector> possible_tiles; // Lista dozwolonych kafelków
|
for(const auto& m: board.getPossibleGlobalBeatings(getPlayerColor())) // Pobieramy dozwolone kafelki docelowe z dozwolonych bić
|
||||||
for(const auto& m: board.getPossibleMovements(selected)) // Pobieramy dozwolone kafelki docelowe z dozwolonych ruchów
|
possible_tiles.push_back(m.end);
|
||||||
possible_tiles.push_back(m.end);
|
board.selectTiles(possible_tiles); // Zaznaczamy je na planszy
|
||||||
board.selectTiles(possible_tiles); // Zaznaczamy je na planszy
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jeżeli pionek nie istnieje w danym miejscu (czyli kliknięto na puste pole),
|
||||||
|
// to znaczy, że jest to ruch docelowy (czyli należy pionek przesunąć):
|
||||||
|
if(!ptr)
|
||||||
|
{
|
||||||
|
// Jeżeli pionek jest poprawnie zaznaczony
|
||||||
|
if(board.getPawn(selected))
|
||||||
|
{
|
||||||
|
// Przesuwamy pionek o ile to możliwe (kliknięte miejsce = position jest naszym docelowym kafelkiem)
|
||||||
|
if(movePawn(Movement(selected, position)))
|
||||||
|
{
|
||||||
|
// Jeżeli się udało, to aktualizujemy pozycję zaznaczonego pionka
|
||||||
|
selected = position;
|
||||||
|
|
||||||
|
// Odznaczamy pionek
|
||||||
|
board.getPawn(selected)->deselect();
|
||||||
|
|
||||||
|
// Odznaczamy kafelki
|
||||||
|
board.deselectTiles();
|
||||||
|
|
||||||
|
// i kończymy turę
|
||||||
|
round = getAIColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::eventHandler()
|
void Game::eventHandler()
|
||||||
{
|
{
|
||||||
// Kontener na zdarzenia
|
// Kontener na zdarzenia
|
||||||
sf::Event event;
|
sf::Event event;
|
||||||
|
|
||||||
// Kolejka zdarzeń
|
// Kolejka zdarzeń
|
||||||
while(window.pollEvent(event))
|
while(window.pollEvent(event))
|
||||||
{
|
|
||||||
// Obsługa zamykania okna gry
|
|
||||||
if(event.type == sf::Event::Closed) window.close();
|
|
||||||
|
|
||||||
// Obsługa myszy
|
|
||||||
if(event.type == sf::Event::MouseButtonPressed)
|
|
||||||
{
|
{
|
||||||
// Lewy klawisz
|
// Obsługa zamykania okna gry
|
||||||
if(event.mouseButton.button == sf::Mouse::Left)
|
if(event.type == sf::Event::Closed) window.close();
|
||||||
|
|
||||||
// Wykonaj turę gracza
|
// Obsługa myszy
|
||||||
executePlayerRound(sf::Vector2f(event.mouseButton.x, event.mouseButton.y));
|
if(event.type == sf::Event::MouseButtonPressed)
|
||||||
|
{
|
||||||
|
// Lewy klawisz
|
||||||
|
if(event.mouseButton.button == sf::Mouse::Left)
|
||||||
|
{
|
||||||
|
// Jeżeli gra jest "w trakcie gry", wykonaj turę gracza
|
||||||
|
if(game_state == GS_RUNNING) executePlayerRound(sf::Vector2f(event.mouseButton.x, event.mouseButton.y));
|
||||||
|
|
||||||
|
// W przeciwnym wypadku zamknij okno
|
||||||
|
else window.close();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::loop()
|
void Game::loop()
|
||||||
{
|
{
|
||||||
// Nieskończona pętla główna gry
|
// Nieskończona pętla główna gry
|
||||||
while(window.isOpen())
|
while(window.isOpen())
|
||||||
{
|
|
||||||
// Przechwytywanie zdarzeń
|
|
||||||
eventHandler();
|
|
||||||
|
|
||||||
// Czyszczenie okna
|
|
||||||
window.clear(sf::Color::Black);
|
|
||||||
|
|
||||||
// Rysowanie planszy
|
|
||||||
board.draw(window);
|
|
||||||
|
|
||||||
// Rysuj HUD
|
|
||||||
drawHUD();
|
|
||||||
|
|
||||||
// Wyświetlenie ekranu
|
|
||||||
window.display();
|
|
||||||
|
|
||||||
// Jeżeli teraz tura należy do AI
|
|
||||||
if(round == getAIColor())
|
|
||||||
{
|
{
|
||||||
// Ruch AI
|
// Jeżeli gra jest "w trakcie gry"
|
||||||
movePawn(minimax.minimax(board));
|
if(game_state == GS_RUNNING)
|
||||||
|
{
|
||||||
// Ustaw turę na gracza
|
// Jeżeli teraz tura należy do AI
|
||||||
round = getPlayerColor();
|
if(round == getAIColor())
|
||||||
|
{
|
||||||
|
// Pobieramy najlepszy ruch AI
|
||||||
|
Movement ai_movement = minimax.getBestMovement(board);
|
||||||
|
|
||||||
|
// Wykonujemy go
|
||||||
|
movePawn(ai_movement);
|
||||||
|
|
||||||
|
// I zaznaczamy na mapie (ułatwienie dla gracza)
|
||||||
|
board.selectMovement(ai_movement);
|
||||||
|
|
||||||
|
// Ustaw turę na gracza
|
||||||
|
round = getPlayerColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualizuj stan gry
|
||||||
|
gameUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Przechwytywanie zdarzeń
|
||||||
|
eventHandler();
|
||||||
|
|
||||||
|
// Czyszczenie okna
|
||||||
|
window.clear(sf::Color::Black);
|
||||||
|
|
||||||
|
// Rysowanie planszy
|
||||||
|
board.draw(window);
|
||||||
|
|
||||||
|
// Rysuj HUD
|
||||||
|
drawHUD();
|
||||||
|
|
||||||
|
// Jeżeli gra się zakończyła ...
|
||||||
|
if(game_state == GS_WIN || game_state == GS_LOSS) displayTheEnd(); // ... wyświetlamy ekran końcowy
|
||||||
|
|
||||||
|
// Wyświetlenie ekranu
|
||||||
|
window.display();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::drawHUD()
|
void Game::drawHUD()
|
||||||
{
|
{
|
||||||
sf::Font font; font.loadFromFile("res/arial.ttf");
|
// Ilość punktów gracza i AI
|
||||||
|
|
||||||
std::stringstream player_score_ss; player_score_ss << "Gracz: " << player_score;
|
|
||||||
std::stringstream ai_score_ss; ai_score_ss << "AI: " << ai_score;
|
|
||||||
|
|
||||||
sf::Text player_score_text(player_score_ss.str(), font);
|
|
||||||
sf::Text ai_score_text(ai_score_ss.str(), font);
|
|
||||||
|
|
||||||
player_score_text.setCharacterSize(24);
|
|
||||||
player_score_text.setColor(sf::Color::White);
|
|
||||||
player_score_text.setPosition(sf::Vector2f(10, TILES_COUNT*TILE_SIZE));
|
|
||||||
|
|
||||||
ai_score_text.setCharacterSize(24);
|
sf::Font font; font.loadFromFile("res/arial.ttf");
|
||||||
ai_score_text.setColor(sf::Color::White);
|
|
||||||
ai_score_text.setPosition(sf::Vector2f(TILES_COUNT*TILE_SIZE - 70, TILES_COUNT*TILE_SIZE));
|
std::stringstream player_score_ss; player_score_ss << "Gracz: " << player_score;
|
||||||
|
std::stringstream ai_score_ss; ai_score_ss << "AI: " << ai_score;
|
||||||
window.draw(player_score_text);
|
|
||||||
window.draw(ai_score_text);
|
sf::Text player_score_text(player_score_ss.str(), font);
|
||||||
|
sf::Text ai_score_text(ai_score_ss.str(), font);
|
||||||
|
|
||||||
|
player_score_text.setCharacterSize(24);
|
||||||
|
player_score_text.setColor(sf::Color::White);
|
||||||
|
player_score_text.setPosition(sf::Vector2f(10, TILES_COUNT*TILE_SIZE));
|
||||||
|
|
||||||
|
ai_score_text.setCharacterSize(24);
|
||||||
|
ai_score_text.setColor(sf::Color::White);
|
||||||
|
ai_score_text.setPosition(sf::Vector2f(TILES_COUNT*TILE_SIZE - 70, TILES_COUNT*TILE_SIZE));
|
||||||
|
|
||||||
|
window.draw(player_score_text);
|
||||||
|
window.draw(ai_score_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::gameUpdate()
|
||||||
|
{
|
||||||
|
// Promuj odpowiednie pionki na damki
|
||||||
|
board.upgrade();
|
||||||
|
|
||||||
|
// Sprawdź stan gry
|
||||||
|
if(getPlayerColor() == CL_WHITE)
|
||||||
|
{
|
||||||
|
if(!board.getNumberOfBlackPawns()) game_state = GS_WIN;
|
||||||
|
if(!board.getNumberOfWhitePawns()) game_state = GS_LOSS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!board.getNumberOfBlackPawns()) game_state = GS_LOSS;
|
||||||
|
if(!board.getNumberOfWhitePawns()) game_state = GS_WIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::displayTheEnd()
|
||||||
|
{
|
||||||
|
// Przyciemniony ekran
|
||||||
|
sf::RectangleShape shadow(sf::Vector2f(TILES_COUNT*TILE_SIZE, TILES_COUNT*TILE_SIZE));
|
||||||
|
shadow.setFillColor(sf::Color(0, 0, 0, 140));
|
||||||
|
shadow.setPosition(0, 0);
|
||||||
|
window.draw(shadow);
|
||||||
|
|
||||||
|
// Napis "Zwycięstwo"/"Porażka"
|
||||||
|
sf::Font font; font.loadFromFile("res/arial.ttf");
|
||||||
|
sf::Text text = (game_state == GS_WIN)?sf::Text(L"Zwycięstwo", font):sf::Text(L"Porażka", font);
|
||||||
|
text.setCharacterSize(60);
|
||||||
|
text.setColor(sf::Color::White);
|
||||||
|
text.setPosition(WINDOW_WIDTH/2-140, WINDOW_HEIGHT/2-60);
|
||||||
|
window.draw(text);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
45
src/main.cpp
45
src/main.cpp
@@ -9,9 +9,46 @@
|
|||||||
#include "../inc/game.hh"
|
#include "../inc/game.hh"
|
||||||
#include "../inc/minimax.hh"
|
#include "../inc/minimax.hh"
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
Game game;
|
|
||||||
|
|
||||||
return 0;
|
// Punkt startowy programu
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// Kolor gracza
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
// Poziom AI
|
||||||
|
int ai;
|
||||||
|
|
||||||
|
// Obsługa błędów i wartości domyślne
|
||||||
|
if(argc != 3)
|
||||||
|
{
|
||||||
|
std::cout << "Użycie: checkers COLOR AI\n\tCOLOR - kolor gracza\n\tAI - poziom AI" << std::endl;
|
||||||
|
color = CL_WHITE;
|
||||||
|
ai = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Obsługa wejścia
|
||||||
|
// Konwersja std::string na Color
|
||||||
|
color = (std::string(argv[1]) == "black")?CL_BLACK:CL_WHITE;
|
||||||
|
|
||||||
|
// Konwersja std::string na int
|
||||||
|
std::stringstream ai_ss; ai_ss << argv[2]; ai_ss >> ai;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zabezpieczenie przed zbyt małym lub dużym poziomem AI
|
||||||
|
if(ai < 2 || ai > 8)
|
||||||
|
{
|
||||||
|
std::cout << "Poziom AI powinien być z przedziału [2, 8]." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Informacja o grze
|
||||||
|
std::cout << "Grasz jako " << ((color==CL_WHITE)?"białe":"czarne") << " z poziomem AI = " << ai << std::endl;
|
||||||
|
|
||||||
|
// Start gry
|
||||||
|
Game game(color, ai);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
225
src/minimax.cpp
225
src/minimax.cpp
@@ -3,136 +3,153 @@
|
|||||||
|
|
||||||
int MiniMax::evaluate(Board& board, const Color& color)
|
int MiniMax::evaluate(Board& board, const Color& color)
|
||||||
{
|
{
|
||||||
// Wycena
|
// Wycena
|
||||||
int value = 0, pawn_value;
|
int value = 0, pawn_value;
|
||||||
|
|
||||||
// Wskaźnik na aktualnie oceniany pionek
|
// Wskaźnik na aktualnie oceniany pionek
|
||||||
Pawn* ptr = NULL;
|
Pawn* ptr = NULL;
|
||||||
|
|
||||||
|
|
||||||
// Przeglądamy całą planszę
|
|
||||||
for(int x = 0; x<TILES_COUNT; ++x)
|
|
||||||
for(int y = 0; y<TILES_COUNT; ++y)
|
|
||||||
{
|
|
||||||
// Jeżeli pionek na tym polu istnieje
|
|
||||||
ptr = board.getPawn(Vector(x, y));
|
|
||||||
if(ptr)
|
|
||||||
{
|
|
||||||
// Jeżeli pionek jest damką:
|
|
||||||
if(ptr->isQueen()) pawn_value = 10;
|
|
||||||
else pawn_value = 1;
|
|
||||||
|
|
||||||
/*** ZASADA TRZECH OBSZARÓW ***/
|
// Przeglądamy całą planszę
|
||||||
{
|
for(int x = 0; x<TILES_COUNT; ++x)
|
||||||
// Jeżeli pionek należy do obszaru III -- waga 1
|
for(int y = 0; y<TILES_COUNT; ++y)
|
||||||
if(((ptr->getPosition().x >= 3) && (ptr->getPosition().y >= 3)) &&
|
{
|
||||||
((ptr->getPosition().x < (TILES_COUNT-3)) && (ptr->getPosition().y < (TILES_COUNT-3))))
|
// Jeżeli pionek na tym polu istnieje
|
||||||
; // więc nie ruszamy
|
ptr = board.getPawn(Vector(x, y));
|
||||||
|
if(ptr)
|
||||||
// Jeżeli pionek należy do obszaru II -- waga 2
|
{
|
||||||
else if(((ptr->getPosition().x >= 2) && (ptr->getPosition().y >= 2)) &&
|
// Jeżeli pionek jest damką:
|
||||||
((ptr->getPosition().x < (TILES_COUNT-2)) && (ptr->getPosition().y < (TILES_COUNT-2))))
|
if(ptr->isQueen()) pawn_value = 10;
|
||||||
pawn_value *= 2;
|
else pawn_value = 1;
|
||||||
|
|
||||||
// W przeciwnym wypadku, zostaje waga 1
|
|
||||||
else
|
|
||||||
pawn_value *= 3;
|
|
||||||
|
|
||||||
}
|
/*** SPRAWDZAMY MOŻLIWE BICIA ***/
|
||||||
|
if(board.isPossibleBeating(Vector(x, y))) pawn_value *= 5;
|
||||||
|
|
||||||
/*** MOŻLIWOŚĆ BICIA ***/
|
/*** ZASADA TRZECH OBSZARÓW ***/
|
||||||
if(board.isPossibleBeating(ptr->getPosition())) pawn_value += 5;
|
{
|
||||||
|
// Jeżeli pionek należy do obszaru III (środkowego) -- waga 1
|
||||||
// Jeżeli NIE jest to pionek należący do gracza zdefiniowanego kolorem color
|
if(((ptr->getPosition().x >= 3) && (ptr->getPosition().y >= 3)) &&
|
||||||
// przemnażamy przez -1
|
((ptr->getPosition().x < (TILES_COUNT-3)) && (ptr->getPosition().y < (TILES_COUNT-3))))
|
||||||
if(ptr->getColor() != color) pawn_value *= -1;
|
pawn_value *= 1; // więc nie ruszamy
|
||||||
|
|
||||||
// Dodajemy pawn_value do wyceny
|
|
||||||
value += pawn_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zwracamy wycenę
|
// Jeżeli pionek należy do obszaru II -- waga 2
|
||||||
return value;
|
else if(((ptr->getPosition().x >= 2) && (ptr->getPosition().y >= 2)) &&
|
||||||
|
((ptr->getPosition().x < (TILES_COUNT-2)) && (ptr->getPosition().y < (TILES_COUNT-2))))
|
||||||
|
pawn_value *= 2;
|
||||||
|
|
||||||
|
// Jeżeli pionek należy do obszaru I (skrajnego) -- waga 3
|
||||||
|
else
|
||||||
|
pawn_value *= 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jeżeli NIE jest to pionek należący do gracza zdefiniowanego kolorem color
|
||||||
|
// przemnażamy przez -1
|
||||||
|
if(ptr->getColor() != color) pawn_value *= -1;
|
||||||
|
|
||||||
|
// Dodajemy pawn_value do wyceny
|
||||||
|
value += pawn_value;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO wykrywanie bicia w heurystyce
|
||||||
|
|
||||||
|
// Zwracamy wycenę
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color MiniMax::getColorFromDepth(int depth)
|
Color MiniMax::getColorFromDepth(int depth)
|
||||||
{
|
{
|
||||||
// Dla parzystych głębokości ruch należy do AI
|
// Dla parzystych głębokości ruch należy do AI
|
||||||
if(depth%2) return AI_COLOR;
|
if(depth%2) return AI_COLOR;
|
||||||
|
|
||||||
// Dla nieparzystych -- do gracza
|
// Dla nieparzystych -- do gracza
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(AI_COLOR == CL_WHITE) return CL_BLACK;
|
if(AI_COLOR == CL_WHITE) return CL_BLACK;
|
||||||
else return CL_WHITE;
|
else return CL_WHITE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MiniMax::alphabeta(Board board, int depth, int alpha, int beta, Movement& best_movement)
|
int MiniMax::alphabeta(Board board, int depth, int alpha, int beta, Movement& best_movement)
|
||||||
{
|
{
|
||||||
// Kolor aktualnego gracza
|
// Kolor aktualnego gracza
|
||||||
Color color = getColorFromDepth(depth);
|
Color color = getColorFromDepth(depth);
|
||||||
|
|
||||||
// Jeżeli jest to liść lub korzeń
|
// Jeżeli jest to liść lub korzeń
|
||||||
if((depth == DEPTH_MAX) || (depth == 0)) return evaluate(board, color);
|
if((depth == DEPTH_MAX) || (depth == 0)) return evaluate(board, color);
|
||||||
|
|
||||||
|
// Jeżeli jest teraz ruch przeciwnika
|
||||||
// Jeżeli jest teraz ruch przeciwnika
|
if(color != AI_COLOR)
|
||||||
if(color != AI_COLOR)
|
|
||||||
{
|
|
||||||
// Dla każdego potomka
|
|
||||||
for(auto& m: board.getPossibleGlobalMovements(color))
|
|
||||||
{
|
{
|
||||||
// Tworzymy nowy stan gry
|
// Dla każdego potomka
|
||||||
Board new_board(board);
|
for(auto& m: board.getPossibleGlobalMovements(color))
|
||||||
|
{
|
||||||
|
// Tworzymy nowy stan gry
|
||||||
|
Board new_board(board);
|
||||||
|
|
||||||
// Wykonujemy ruch
|
// Wykonujemy ruch
|
||||||
new_board.movePawn(m);
|
new_board.movePawn(m);
|
||||||
|
|
||||||
// Pobieramy wartość MIN (czyli gracz minimalizuje zysk AI)
|
// Pobieramy wartość MIN (czyli gracz minimalizuje zysk AI)
|
||||||
beta = std::min(beta, alphabeta(new_board, depth+1, alpha, beta, best_movement));
|
beta = std::min(beta, alphabeta(new_board, depth+1, alpha, beta, best_movement));
|
||||||
|
|
||||||
// Jeżeli alfa >= beta odcinamy gałąź alpha
|
// Jeżeli alfa >= beta odcinamy gałąź alfa
|
||||||
if(alpha >= beta) break;
|
if(alpha >= beta) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zwracamy wartość najlepszego ruchu
|
||||||
|
return beta;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Jeśli jest teraz ruch AI
|
// Jeśli jest teraz ruch AI
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// Dla każdego potomka
|
// Dla każdego potomka
|
||||||
for(auto& m: board.getPossibleGlobalMovements(color))
|
for(auto& m: board.getPossibleGlobalMovements(color))
|
||||||
{
|
{
|
||||||
// Tworzymy nowy stan gry
|
// Tworzymy nowy stan gry
|
||||||
Board new_board(board);
|
Board new_board(board);
|
||||||
|
|
||||||
// Wykonujemy ruch
|
|
||||||
new_board.movePawn(m);
|
|
||||||
|
|
||||||
// Pobieramy wartość MAX (czyli AI maksymalizuje własny zysk)
|
// Wykonujemy ruch
|
||||||
alpha = std::max(alpha, alphabeta(new_board, depth+1, alpha, beta, best_movement));
|
new_board.movePawn(m);
|
||||||
|
|
||||||
// Zwracamy w referencji ruch (dążymy do tego, aby na poziomie głębokości = 1 mieć
|
// Pobieramy wartość stanu gry dla potomka
|
||||||
// ruch, za pomocą którego doszliśmy do najlepszego rozwiązania według strategii minimax)
|
int temp = alphabeta(new_board, depth+1, alpha, beta, best_movement);
|
||||||
best_movement = m;
|
|
||||||
|
|
||||||
// Jeżeli alfa >= beta odcinamy gałąź beta
|
|
||||||
if(alpha >= beta) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zwracamy wartość najlepszego ruchu
|
// Liczymy MAX (czyli AI maksymalizuje własny zysk)
|
||||||
return alpha;
|
// oraz jednocześnie warunek najlepszego ruchu
|
||||||
|
if(temp > alpha)
|
||||||
|
{
|
||||||
|
// Jeśli temp > alpha, przypisujemy alpha a= temp (z definicji MAX(a, b))
|
||||||
|
alpha = temp;
|
||||||
|
|
||||||
|
// Na poziomie rekurencji = 1 zwracamy w referencji
|
||||||
|
// ruch, za pomocą którego doszliśmy do najlepszego rozwiązania według strategii minimax
|
||||||
|
if(depth==1) best_movement = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jeżeli alfa >= beta odcinamy gałąź beta
|
||||||
|
if(alpha >= beta) break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zwracamy wartość najlepszego ruchu
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Movement MiniMax::minimax(Board board)
|
Movement MiniMax::getBestMovement(Board board)
|
||||||
{
|
{
|
||||||
// Tworzymy bufor na ruch
|
// Tworzymy bufor na ruch
|
||||||
Movement best_movement;
|
Movement best_movement;
|
||||||
|
|
||||||
// Pobieramy algorytmem minimax z cięciem alfa-beta najlepszy ruch
|
// Pobieramy algorytmem minimax z cięciem alfa-beta najlepszy ruch
|
||||||
alphabeta(board, 1, -INF, INF, best_movement);
|
alphabeta(board, 1, -INF, INF, best_movement);
|
||||||
|
|
||||||
// Zwracamy najlepszy ruch
|
// Zwracamy najlepszy ruch
|
||||||
return best_movement;
|
return best_movement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user