-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
1,195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#include "classes/Board.h" | ||
#include <SFML/Graphics.hpp> | ||
|
||
Board::Board(const int n) :size(n) { | ||
field = new Field * [n]; | ||
for (int i = 0; i < n; ++i) | ||
field[i] = new Field[n]; | ||
int x, y; | ||
for (x = 0; x < n; x++) { | ||
for (y = 0; y < n; y++) { | ||
field[x][y].setpos(x, y); | ||
} | ||
} | ||
sign_x.loadFromFile("images/x.png"); | ||
sign_o.loadFromFile("images/o.png"); | ||
win_x.loadFromFile("images/win_x.png"); | ||
win_o.loadFromFile("images/win_o.png"); | ||
} | ||
|
||
Board::~Board() { | ||
delete[] field; | ||
} | ||
|
||
Field* Board::get_field(const int x, const int y) { | ||
return &(field[x][y]); | ||
} | ||
|
||
void Board::unmark_all() { | ||
int x, y; | ||
for (x = 0; x < size; x++) { | ||
for (y = 0; y < size; y++) { | ||
field[x][y].unmark(); | ||
} | ||
} | ||
} | ||
|
||
bool Board::is_full() { | ||
int x, y; | ||
for (x = 0; x < size; x++) { | ||
for (y = 0; y < size; y++) { | ||
if (field[x][y].get_owner() == nullptr) return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
void Board::draw_grid(sf::RenderWindow& window) { | ||
int x, y; | ||
float posX, posY; | ||
|
||
float lr_margin = 50; | ||
|
||
float btn_size = (float)((window.getSize().x - (2 * lr_margin)) / size) - 2 * 1; | ||
|
||
float top_margin = window.getSize().y - lr_margin - (btn_size + 2) * size; | ||
|
||
posX = lr_margin; | ||
posY = top_margin; | ||
|
||
for (x = 0; x < size; x++) { | ||
for (y = 0; y < size; y++) { | ||
field[x][y].button.setSize({ btn_size, btn_size }); | ||
field[x][y].button.setPosition(posX, posY); | ||
|
||
if (field[x][y].get_owner() != nullptr) { | ||
if (field[x][y].get_owner()->get_symbol() == 'o') { | ||
if (field[x][y].is_marked()) field[x][y].button.setTexture(&win_o); | ||
else field[x][y].button.setTexture(&sign_o); | ||
} | ||
else { | ||
if (field[x][y].is_marked()) field[x][y].button.setTexture(&win_x); | ||
else field[x][y].button.setTexture(&sign_x); | ||
} | ||
} | ||
|
||
field[x][y].draw(window); | ||
posY += btn_size + 2; | ||
} | ||
posX += btn_size + 2; | ||
posY = top_margin; | ||
} | ||
} | ||
|
||
Field* Board::get_clicked_field(sf::RenderWindow& window) { | ||
int x, y; | ||
for (y = 0; y < size; y++) { | ||
for (x = 0; x < size; x++) { | ||
if (field[x][y].isMouseOver(window)) { | ||
return &(field[x][y]); | ||
} | ||
} | ||
} | ||
return nullptr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#include "classes/Button.h" | ||
#include <SFML/Graphics.hpp> | ||
|
||
Button::Button() { | ||
button.setFillColor(sf::Color::White); | ||
} | ||
|
||
Button::Button(sf::Vector2f pos, sf::Vector2f size) { | ||
button.setPosition(pos.x, pos.y); | ||
button.setSize({ size.x, size.y }); | ||
} | ||
|
||
bool Button::isMouseOver(sf::RenderWindow& window) { | ||
int mouseX = sf::Mouse::getPosition(window).x; | ||
int mouseY = sf::Mouse::getPosition(window).y; | ||
|
||
float btnPosX = button.getPosition().x; | ||
float btnPosY = button.getPosition().y; | ||
|
||
float btnWidth = btnPosX + button.getLocalBounds().width; | ||
float btnHeight = btnPosY + button.getLocalBounds().height; | ||
|
||
return (mouseX > btnPosX && mouseX < btnWidth&& mouseY < btnHeight&& mouseY > btnPosY); | ||
} | ||
|
||
void Button::draw_button(sf::RenderWindow& window) { | ||
window.draw(button); | ||
text.draw_text(window); | ||
} | ||
|
||
void Button::set_position(sf::Vector2f pos) { | ||
button.setPosition(pos.x, pos.y); | ||
} | ||
|
||
void Button::set_size(sf::Vector2f btn_size) { | ||
button.setSize({ btn_size.x, btn_size.y }); | ||
} | ||
|
||
void Button::set_texture(const char* filename) { | ||
texture.loadFromFile(filename); | ||
button.setTexture(&texture); | ||
} | ||
|
||
void Button::set_border(int width, sf::Color color) { | ||
button.setOutlineThickness(width); | ||
button.setOutlineColor(color); | ||
} | ||
|
||
void Button::set_display_text(std::string new_text, int size) { | ||
|
||
text.set_display_text(new_text); | ||
text.set_size(size); | ||
|
||
float posX = button.getPosition().x + ((button.getLocalBounds().width - 2 * button.getOutlineThickness()) - text.getLocalBounds().width) / 2; | ||
float posY = -3 + button.getPosition().y + ((button.getLocalBounds().height - 2 * button.getOutlineThickness()) - text.getLocalBounds().height) / 2; | ||
|
||
text.set_position(posX, posY); | ||
|
||
} | ||
|
||
void Button::set_color(int r, int g, int b) { | ||
button.setFillColor(sf::Color(r, g, b, 255)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#include "classes/Field.h" | ||
#include <SFML/Graphics.hpp> | ||
|
||
Field::Field() { | ||
mark_as_winner = false; | ||
x_pos = y_pos = -1; | ||
owner = nullptr; | ||
|
||
button.setFillColor(sf::Color::White); | ||
button.setOutlineThickness(1.f); | ||
button.setOutlineColor(sf::Color::Black); | ||
} | ||
|
||
Field::~Field() { | ||
delete owner; | ||
} | ||
|
||
int Field::get_x() const { | ||
return x_pos; | ||
} | ||
|
||
int Field::get_y() const { | ||
return y_pos; | ||
} | ||
|
||
Player* Field::get_owner() { | ||
return owner; | ||
} | ||
|
||
void Field::mark() { | ||
mark_as_winner = true; | ||
} | ||
|
||
void Field::unmark() { | ||
mark_as_winner = false; | ||
} | ||
|
||
bool Field::is_marked() { | ||
return mark_as_winner; | ||
} | ||
|
||
void Field::setpos(int x, int y) { | ||
x_pos = x; | ||
y_pos = y; | ||
} | ||
|
||
void Field::set_owner(Player* new_owner) { | ||
owner = new_owner; | ||
} | ||
|
||
void Field::draw(sf::RenderWindow& window) { | ||
window.draw(button); | ||
} | ||
|
||
bool Field::isMouseOver(sf::RenderWindow& window) { | ||
int mouseX = sf::Mouse::getPosition(window).x; | ||
int mouseY = sf::Mouse::getPosition(window).y; | ||
|
||
float btnPosX = button.getPosition().x; | ||
float btnPosY = button.getPosition().y; | ||
|
||
float btnWidth = btnPosX + button.getLocalBounds().width; | ||
float btnHeight = btnPosY + button.getLocalBounds().height; | ||
|
||
return (mouseX > btnPosX && mouseX < btnWidth&& mouseY < btnHeight&& mouseY > btnPosY); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#include "classes/Game.h" | ||
#include <SFML/Graphics.hpp> | ||
|
||
Game::Game(const int field_size, const int req_length, bool is_ai) : size(field_size), length(req_length) { | ||
finished = false; | ||
board = new Board(field_size); | ||
winner = nullptr; | ||
players[0] = new Player('o', false); | ||
players[1] = new Player('x', is_ai); | ||
} | ||
|
||
Game::~Game() { | ||
delete winner; | ||
delete board; | ||
} | ||
|
||
Board* Game::get_board() { | ||
return board; | ||
} | ||
|
||
Player* Game::get_winner() { | ||
return winner; | ||
} | ||
|
||
void Game::set_field_owner(int x, int y, char sign) { | ||
Player* new_owner; | ||
|
||
if (players[0]->get_symbol() == sign) new_owner = players[0]; | ||
else if (players[1]->get_symbol() == sign) new_owner = players[1]; | ||
else return; | ||
|
||
board->get_field(x, y)->set_owner(new_owner); | ||
} | ||
|
||
void Game::remove_field_owner(int x, int y) { | ||
board->get_field(x, y)->set_owner(nullptr); | ||
} | ||
|
||
Player* Game::get_player_by_sign(char sign) { | ||
if (players[0]->get_symbol() == sign) return players[0]; | ||
else if (players[1]->get_symbol() == sign) return players[1]; | ||
else return nullptr; | ||
} | ||
bool Game::is_finished() { | ||
return finished; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#include "classes/Game.h" | ||
#include <SFML/Graphics.hpp> | ||
#include <iostream> | ||
|
||
Field* Game::random_empty_field() { | ||
if (finished) return nullptr; | ||
int x, y; | ||
Field* field; | ||
srand(time(NULL)); | ||
while (true) { | ||
x = rand() % size; | ||
y = rand() % size; | ||
field = board->get_field(x, y); | ||
if (field->get_owner() == nullptr) return field; | ||
} | ||
} | ||
|
||
Field* Game::get_ai_move(int difficulty) { | ||
|
||
int x, y, rate = 0, i, j, win, win_points, block_points, win_diff, block_diff; | ||
int minimal = 100000; | ||
|
||
win = length; | ||
|
||
win_points = difficulty == 2 ? 0 : 1005; | ||
win_diff = difficulty == 2 ? 0 : 15; | ||
block_points = 1000; | ||
block_diff = 5; | ||
|
||
|
||
|
||
//allocate rating table | ||
int** rating = new int* [size]; | ||
for (i = 0; i < size; ++i) { | ||
rating[i] = new int[size]; | ||
} | ||
//fill array with zeros | ||
for (i = 0; i < size; i++) { | ||
for (j = 0; j < size; j++) { | ||
rating[i][j] = 0; | ||
} | ||
} | ||
|
||
//give points value to the field | ||
for (win = length; win > 1; win--) { | ||
|
||
for (i = 0; i < size; i++) { | ||
for (j = 0; j < size; j++) { | ||
|
||
|
||
if (board->get_field(i, j)->get_owner() == nullptr) { | ||
|
||
//Try to put AI's symbol | ||
set_field_owner(i, j, 'x'); | ||
if (look_for_win(win)) { | ||
rating[i][j] += win_points; | ||
} | ||
finished = false; | ||
board->unmark_all(); | ||
remove_field_owner(i, j); | ||
|
||
//Try to put user's symbol | ||
set_field_owner(i, j, 'o'); | ||
if (look_for_win(win)) { | ||
rating[i][j] += block_points; | ||
} | ||
finished = false; | ||
board->unmark_all(); | ||
remove_field_owner(i, j); | ||
} | ||
|
||
} | ||
} | ||
|
||
win_points -= win_diff; | ||
block_points -= block_diff; | ||
|
||
} | ||
|
||
//Look for most profitable field | ||
for (i = 0; i < size; i++) { | ||
for (j = 0; j < size; j++) { | ||
if (rating[i][j] > rate) { | ||
rate = rating[i][j]; | ||
x = i; | ||
y = j; | ||
} | ||
} | ||
} | ||
|
||
//Find lowest value | ||
for (i = 0; i < size; i++) { | ||
for (j = 0; j < size; j++) { | ||
if (rating[i][j] < minimal && board->get_field(i, j)->get_owner() == nullptr) { | ||
minimal = rating[i][j]; | ||
} | ||
} | ||
} | ||
|
||
//cleanup | ||
for (i = 0; i < size; ++i) { | ||
delete[] rating[i]; | ||
} | ||
delete[] rating; | ||
rating = NULL; | ||
|
||
//return result | ||
if (rate == minimal) return random_empty_field(); | ||
else return board->get_field(x, y); | ||
} |
Oops, something went wrong.