summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/helper.cpp265
-rw-r--r--src/helper.hpp104
-rw-r--r--src/random.cpp27
-rw-r--r--src/random.hpp19
-rw-r--r--src/timedLatch.cpp38
-rw-r--r--src/timedLatch.hpp22
-rw-r--r--src/ur.cpp334
7 files changed, 809 insertions, 0 deletions
diff --git a/src/helper.cpp b/src/helper.cpp
new file mode 100644
index 0000000..8d6f3ce
--- /dev/null
+++ b/src/helper.cpp
@@ -0,0 +1,265 @@
+#include "helper.hpp"
+#include <iostream>
+
+std::shared_ptr<std::vector<sf::Texture>>
+loadTextures(const char* path)
+{
+ int sprite_width = SPRITE_SIZE, sprite_height = SPRITE_SIZE;
+ sf::Image textureAtlas;
+ if (!textureAtlas.loadFromFile(path)) {
+ std::cerr << "Unable to load textures from file: " << path << std::endl;
+ throw std::runtime_error("Unable to load spritesheet");
+ }
+
+ textureAtlas.createMaskFromColor(GLOBAL_MASK);
+ auto imageSize = textureAtlas.getSize();
+
+ auto textures = std::make_shared<std::vector<sf::Texture>>();
+
+ for (int y = 0; y < imageSize.y; y += sprite_height) {
+ for (int x = 0; x < imageSize.x; x += sprite_width) {
+ sf::Texture t;
+ t.loadFromImage(textureAtlas,
+ sf::IntRect(x, y, sprite_width, sprite_height));
+ textures->push_back(t);
+ }
+ }
+ return textures;
+}
+
+// increment through the textures
+inline int
+next(int* p, int max)
+{
+ int i = *p;
+ (*p) = (i + 1) % max;
+ return i;
+}
+
+std::shared_ptr<std::vector<sf::Sprite>>
+createBoard(std::shared_ptr<std::vector<sf::Texture>> textures)
+{
+ auto sprites = std::make_shared<std::vector<sf::Sprite>>();
+ sf::Texture& star_texture = (*textures)[STAR_TILE];
+ int blank_idx = 0;
+ int sp_idx = 0;
+ // p1 pieces
+ // p1 star
+ {
+ sf::Sprite s;
+ s.setTexture(star_texture);
+ s.setPosition(pos(3, 5));
+ sprites->push_back(s);
+ }
+ // p1 start
+ for (int i = 0; i < 3; i++) {
+ sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]];
+ sf::Sprite s;
+ s.setTexture(t);
+ s.setPosition(pos(4 + i, 5));
+ sprites->push_back(s);
+ }
+ // p1 end
+ {
+ sf::Sprite goal;
+ goal.setTexture((*textures)[P1_END]);
+ goal.setPosition(pos(8, 5));
+ sprites->push_back(goal);
+
+ sf::Sprite end_star;
+ end_star.setTexture(star_texture);
+ end_star.setPosition(pos(9, 5));
+ sprites->push_back(end_star);
+
+ sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]];
+ sf::Sprite s;
+ s.setTexture(t);
+ s.setPosition(pos(10, 5));
+ sprites->push_back(s);
+ }
+ // center pieces
+ for (int i = 0; i < 8; i++) {
+ sf::Sprite s;
+ if (i == 3) {
+ s.setTexture(star_texture);
+ } else {
+ sf::Texture& t = (*textures)[BLANK_TILES[next(&blank_idx, 3)]];
+ s.setTexture(t);
+ }
+ s.setPosition(pos(3 + i, 4));
+ sprites->push_back(s);
+ }
+ // p2 pieces
+ // p2 star
+ {
+ sf::Sprite s;
+ s.setTexture(star_texture);
+ s.setPosition(pos(3, 3));
+ sprites->push_back(s);
+ }
+ // p2 start
+ for (int i = 0; i < 3; i++) {
+ sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]];
+ sf::Sprite s;
+ s.setTexture(t);
+ s.setPosition(pos(4 + i, 3));
+ sprites->push_back(s);
+ }
+ // p2 end
+ {
+ sf::Sprite goal;
+ goal.setTexture((*textures)[P2_END]);
+ goal.setPosition(pos(8, 3));
+ sprites->push_back(goal);
+
+ sf::Sprite end_star;
+ end_star.setTexture(star_texture);
+ end_star.setPosition(pos(9, 3));
+ sprites->push_back(end_star);
+
+ sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]];
+ sf::Sprite end_tile;
+ end_tile.setTexture(t);
+ end_tile.setPosition(pos(10, 3));
+ sprites->push_back(end_tile);
+ }
+
+ return sprites;
+}
+
+sf::Font
+loadFont()
+{
+ sf::Font font;
+ if (!font.loadFromFile("./res/DejaVuSansMono.ttf")) {
+ std::cerr << "Unable to load font" << std::endl;
+ throw std::runtime_error("Unable to load font");
+ }
+ return font;
+}
+
+std::shared_ptr<struct piece_t>
+createPiece(int id, sf::Texture& texture)
+{
+
+ sf::Sprite s(texture);
+ auto p = std::make_shared<struct piece_t>();
+ p->id = id;
+ p->sprite = s;
+
+ return p;
+}
+
+std::shared_ptr<struct player_t>
+createPlayer(sf::Texture& texture)
+{
+ std::shared_ptr<struct player_t> player = std::make_shared<struct player_t>();
+ player->score = 0;
+ player->pieces = std::make_shared<std::vector<struct piece_t>>();
+ for (int i = 0; i < NUM_PIECES; i++) {
+ player->pieces->push_back(*createPiece(i + 1, texture));
+ }
+
+ return player;
+}
+
+std::shared_ptr<std::vector<struct dice_t>>
+createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture)
+{
+ auto dice = std::make_shared<std::vector<struct dice_t>>();
+
+ // create dice, even 0 odds 1
+ // there are 8 dice results int total
+ // 4 potential 0s
+ // 4 potential 1s
+ // The dice will be rendered in pairs
+ // [0, 1] will be the left most die
+ // [2, 3] will be the second
+ // ... and so on
+ // Since a die can only have 2 results (0 or 1)
+ // To simplify how we will be placing them, the results of the roll
+ // will dictate which value each die gets
+ for (int i = 0; i < 8; i++) {
+ if (i % 2 == 0) {
+ sf::Sprite s;
+ s.setTexture(die0Texture);
+ struct dice_t die = { 0, true, s };
+ dice->push_back(die);
+ } else {
+ sf::Sprite s;
+ s.setTexture(die1Texture);
+ struct dice_t die = { 1, false, s };
+ dice->push_back(die);
+ }
+ }
+
+ return dice;
+}
+
+std::shared_ptr<std::vector<sf::Sprite>>
+createRollSprites(sf::Texture& t1, sf::Texture& t2)
+{
+ auto sprites = std::make_shared<std::vector<sf::Sprite>>();
+
+ sprites->push_back(sf::Sprite(t1));
+ sprites->push_back(sf::Sprite(t2));
+
+ return sprites;
+}
+
+void
+makeNum(sf::Sprite* sprite_ptr,
+ int num,
+ std::shared_ptr<std::vector<sf::Texture>> textures)
+{
+ sf::Texture& t = (*textures)[NUMS_TILES[num]];
+ sprite_ptr->setTexture(t);
+};
+
+bool
+clickedPiece(sf::Vector2i mousePosition, struct piece_t* piece)
+{
+ return piece->sprite.getGlobalBounds().contains(mousePosition.x,
+ mousePosition.y);
+}
+
+bool
+canMovePiece(struct piece_t* piece,
+ int roll,
+ std::shared_ptr<std::vector<struct piece_t>> myPieces,
+ std::shared_ptr<std::vector<struct piece_t>> enemyPieces)
+{
+ int next = piece->position + roll;
+
+ // rolled passed the exit
+ if (next > EXIT_SPACE) {
+ return false;
+ }
+
+ // colliding with another piece
+ for (struct piece_t& p : (*myPieces)) {
+ // cannot move onto your own piece
+ if (p.id != piece->id && p.position == next) {
+ return false;
+ }
+ }
+
+ // can't attack in safe square
+ for (struct piece_t& p : (*enemyPieces)) {
+ // cannot move onto a protected enemy piece
+ if (next == SAFE_SPACE && p.position == SAFE_SPACE) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// This function takes in an row and col we want to put the sprite in
+// and translate it to a real position in the view
+// This is because we've ZOOMed in an that adjusts the entire view.
+sf::Vector2f
+pos(float c, float r)
+{
+ return { c * SPRITE_SIZE, r * SPRITE_SIZE };
+}
diff --git a/src/helper.hpp b/src/helper.hpp
new file mode 100644
index 0000000..3e7ffbb
--- /dev/null
+++ b/src/helper.hpp
@@ -0,0 +1,104 @@
+#ifndef UR_HELPER_H
+#define UR_HELPER_H
+
+#include <SFML/Graphics.hpp>
+#include <memory>
+#include <vector>
+
+// BOARD LAYOUT [0, 1, 2, 3](start) [4,5,6,7,8,9,10,11](middle), [12,13](end)
+
+static const unsigned int SPRITE_SIZE = 16;
+static const unsigned int NUM_PIECES = 7;
+static const unsigned int SAFE_SPACE = 7; // 0-indexed
+static const unsigned int EXIT_SPACE = 14; // final space + 1
+static const float ZOOM = 0.5f;
+static const float SPRITE_ROWS = 9.f;
+static const float SPRITE_COLS = 14.f;
+static const float SCR_W = SPRITE_SIZE / ZOOM * SPRITE_COLS / ZOOM;
+static const float SCR_H = SPRITE_SIZE / ZOOM * SPRITE_ROWS / ZOOM;
+static const int P1_PIECE = 19;
+static const int P2_PIECE = 18;
+static const int P1_BOARD_TILES[2] = { 0, 1 };
+static const int P2_BOARD_TILES[2] = { 2, 3 };
+static const int STAR_TILE = 4;
+static const int BLANK_TILES[3] = { 5, 6, 7 };
+static const int P1_END = 22;
+static const int P2_END = 23;
+static const int DIE_0 = 17;
+static const int DIE_1 = 16;
+static const int NUMS_TILES[8] = { 8, 9, 10, 11, 12, 13, 14, 15 };
+static const int ROLL_TILES[2] = { 20, 21 };
+
+static const char* TITLE = "Royal Game of Ur";
+static const sf::Color GLOBAL_MASK(255, 0, 255, 255);
+
+enum GameState
+{
+ WAITING,
+ ROLLING,
+ PLACING,
+ GAME_OVER
+};
+
+struct piece_t
+{
+ int id;
+ int position;
+ sf::Sprite sprite;
+};
+
+struct player_t
+{
+ int score;
+ std::shared_ptr<std::vector<struct piece_t>> pieces;
+};
+
+struct dice_t
+{
+ int value;
+ bool show;
+ sf::Sprite sprite;
+};
+
+std::shared_ptr<std::vector<sf::Texture>>
+loadTextures(const char* path);
+
+std::shared_ptr<std::vector<sf::Sprite>>
+createBoard(std::shared_ptr<std::vector<sf::Texture>> textures);
+
+sf::Font
+loadFont();
+
+std::shared_ptr<struct player_t>
+createPlayer(sf::Texture& pieceTexture);
+
+std::shared_ptr<struct piece_t>
+createPiece(int id, sf::Texture& texture);
+
+std::shared_ptr<std::vector<struct dice_t>>
+createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture);
+
+std::shared_ptr<std::vector<sf::Sprite>>
+createRollSprites(sf::Texture& t1, sf::Texture& t2);
+
+void
+makeNum(sf::Sprite* sprite_ptr,
+ int num,
+ std::shared_ptr<std::vector<sf::Texture>> textures);
+
+bool
+clickedPiece(sf::Vector2i mousePosition, std::shared_ptr<struct piece_t> piece);
+
+bool
+canMovePiece(std::shared_ptr<struct piece_t> piece,
+ int roll,
+ std::shared_ptr<std::vector<struct piece_t>> myPieces,
+ std::shared_ptr<std::vector<struct piece_t>> enemyPieces);
+
+std::vector<int>
+getLegalMoves(std::shared_ptr<struct player_t> activePlayer,
+ std::shared_ptr<struct player_t> opponent);
+
+sf::Vector2f
+pos(float c, float r);
+#endif
diff --git a/src/random.cpp b/src/random.cpp
new file mode 100644
index 0000000..e94b191
--- /dev/null
+++ b/src/random.cpp
@@ -0,0 +1,27 @@
+#include "random.hpp"
+#include <chrono>
+#include <cmath>
+
+namespace ur {
+
+Random::Random(int min, int max)
+{
+ this->min = min;
+ this->max = max;
+ // setup the random stuff
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ this->engine = std::default_random_engine(seed);
+
+ // setup distribution
+ float range = float(max - min);
+ this->distribution =
+ std::normal_distribution<float>(range / 2.f, range / 4.f);
+}
+
+int
+Random::next()
+{
+ return std::round(this->distribution(this->engine));
+}
+
+}
diff --git a/src/random.hpp b/src/random.hpp
new file mode 100644
index 0000000..e74267a
--- /dev/null
+++ b/src/random.hpp
@@ -0,0 +1,19 @@
+#ifndef UR_RANDOM_H
+#define UR_RANDOM_H
+
+#include <random>
+namespace ur {
+class Random
+{
+public:
+ Random(int min, int max);
+ int next();
+
+private:
+ int min;
+ int max;
+ std::default_random_engine engine;
+ std::normal_distribution<float> distribution;
+};
+}
+#endif
diff --git a/src/timedLatch.cpp b/src/timedLatch.cpp
new file mode 100644
index 0000000..66714a5
--- /dev/null
+++ b/src/timedLatch.cpp
@@ -0,0 +1,38 @@
+#include "timedLatch.hpp"
+
+namespace ur {
+
+TimedLatch::TimedLatch(sf::Time duration)
+{
+ this->duration = duration;
+ this->clock = sf::Clock();
+ this->isStarted = false;
+};
+
+void
+TimedLatch::start()
+{
+ this->clock.restart();
+ this->isStarted = true;
+};
+
+bool
+TimedLatch::is_running()
+{
+ return this->isStarted && this->clock.getElapsedTime() < duration;
+};
+
+bool
+TimedLatch::is_completed()
+{
+
+ return this->isStarted && this->clock.getElapsedTime() >= duration;
+};
+
+void
+TimedLatch::reset()
+{
+ this->isStarted = false;
+};
+
+}
diff --git a/src/timedLatch.hpp b/src/timedLatch.hpp
new file mode 100644
index 0000000..77c7d49
--- /dev/null
+++ b/src/timedLatch.hpp
@@ -0,0 +1,22 @@
+#ifndef UR_TIMEDLATCH_H
+#define UR_TIMEDLATCH_H
+#include <SFML/System.hpp>
+
+namespace ur {
+class TimedLatch
+{
+public:
+ TimedLatch(sf::Time duration);
+ void start();
+ void reset();
+ bool is_running();
+ bool is_completed();
+
+private:
+ bool isStarted;
+ sf::Time duration;
+ sf::Clock clock; // internal sfml clock to manage time
+};
+}
+
+#endif
diff --git a/src/ur.cpp b/src/ur.cpp
new file mode 100644
index 0000000..dc61eb3
--- /dev/null
+++ b/src/ur.cpp
@@ -0,0 +1,334 @@
+#include "helper.hpp"
+#include "random.hpp"
+#include "timedLatch.hpp"
+#include <SFML/Graphics.hpp>
+#include <SFML/System.hpp>
+#include <iostream>
+#include <string>
+
+const char* TEXTURE_PATH = "./res/ur.png";
+const float PAD = 32.f;
+const float PIECE_PAD = 8.f;
+const float TEXT_OFFSET = 8.f;
+const sf::Color BG_COLOR = sf::Color(66, 47, 81, 255);
+const sf::Color SEMI_TRANSPARENT = sf::Color(255, 255, 255, 128);
+
+ur::Random dice_rand(0, 1); // 50/50 random
+GameState state = GameState::WAITING;
+GameState prev_state = GameState::WAITING;
+struct piece_t* grabbed_piece = nullptr;
+sf::Vector2f grabbed_piece_origin;
+
+int turn_roll = 0;
+bool mouse_left_locked = false;
+
+inline void
+change_state(GameState next)
+{
+ std::cout << "GameState == " << next << std::endl;
+ prev_state = state;
+ state = next;
+}
+
+// p1 = false, p2 = true
+bool turn_tracker = false;
+int rolling_frame = 0;
+
+inline void
+next(int* i, int max)
+{
+ (*i) = ((*i) + 1) % max;
+}
+
+inline void
+next_turn()
+{
+ turn_tracker = !turn_tracker;
+ change_state(GameState::WAITING);
+}
+
+inline bool
+p1_turn()
+{
+ return !turn_tracker;
+}
+
+inline bool
+p2_turn()
+{
+ return turn_tracker;
+}
+
+inline void
+render_dice(sf::RenderWindow* window,
+ std::shared_ptr<std::vector<struct dice_t>> dice,
+ std::shared_ptr<std::vector<sf::Sprite>> roll_sprites,
+ std::shared_ptr<std::vector<sf::Texture>> textures,
+ sf::Sprite* roll_result,
+ ur::TimedLatch* animation_timer,
+ ur::TimedLatch* animation_frame_timer)
+{
+
+ if (animation_timer->is_completed()) {
+ animation_timer->reset();
+ change_state(GameState::PLACING);
+ int rolls[4] = {
+ dice_rand.next(), dice_rand.next(), dice_rand.next(), dice_rand.next()
+ };
+ // draw roll result
+ for (int i = 0; i < 8; i++) {
+ auto& die = (*dice)[i];
+ die.show = die.value == rolls[i / 2];
+ }
+ // set roll result
+ for (int r : rolls)
+ turn_roll += r;
+ }
+
+ // draw dice
+ int dice_r, dice_c, roll_r, roll_c;
+ if (p1_turn()) {
+ dice_r = 6;
+ dice_c = 11;
+ roll_r = dice_r + 2;
+ roll_c = dice_c;
+ } else {
+ dice_r = 1;
+ dice_c = 11;
+ roll_r = dice_r - 1;
+ roll_c = dice_c;
+ }
+
+ if (state == GameState::PLACING) {
+ // draw roll text
+ makeNum(roll_result, turn_roll, textures);
+ window->draw(*roll_result);
+ } else if (state == GameState::ROLLING) {
+ // if completed update dice sprites
+ if (animation_frame_timer->is_completed()) {
+ // iterate over each pair of dice sprites
+ // and show whichever matches the roll
+ for (int i = 0; i < 8; i += 2) {
+ int result = dice_rand.next();
+ (*dice)[i].show = result == 0;
+ (*dice)[i + 1].show = result == 1;
+ }
+ }
+ // make sure we're started!
+ // note - this should come after the completed check otherwise we'll always
+ // restart it
+ if (!animation_frame_timer->is_running()) {
+ animation_frame_timer->start();
+ }
+
+ } else {
+ // draw initial values
+ // draw the 0s
+ int c = dice_c, r = dice_r;
+ for (int i = 0; i < 8; i += 2) {
+ auto& die = (*dice)[i];
+ die.sprite.setPosition(pos(c++, r));
+ window->draw(die.sprite);
+ if (i == 2) {
+ c = dice_c;
+ r += 1;
+ }
+ }
+ }
+
+ int c = dice_c, r = dice_r;
+ int i = 0;
+ for (auto& die : (*dice)) {
+ if (die.show) {
+ die.sprite.setPosition(pos(c++, r));
+ window->draw(die.sprite);
+ if (++i == 2) {
+ c = dice_c;
+ r += 1;
+ }
+ }
+ }
+ c = roll_c, r = roll_r;
+ for (auto& s : (*roll_sprites)) {
+ s.setPosition(pos(c++, r));
+ }
+}
+
+int
+main()
+{
+ const std::shared_ptr<std::vector<sf::Texture>> textures =
+ loadTextures(TEXTURE_PATH);
+
+ const std::shared_ptr<std::vector<sf::Sprite>> board = createBoard(textures);
+
+ const std::shared_ptr<struct player_t> p1 =
+ createPlayer((*textures)[P1_PIECE]);
+
+ const std::shared_ptr<struct player_t> p2 =
+ createPlayer((*textures)[P2_PIECE]);
+
+ const std::shared_ptr<std::vector<sf::Sprite>> roll_sprites =
+ createRollSprites((*textures)[ROLL_TILES[0]], (*textures)[ROLL_TILES[1]]);
+
+ const std::shared_ptr<std::vector<struct dice_t>> dice =
+ createAllDice((*textures)[DIE_0], (*textures)[DIE_1]);
+
+ sf::Sprite p1Score;
+ p1Score.setPosition(pos(0, SPRITE_ROWS - 1));
+ makeNum(&p1Score, 0, textures);
+
+ sf::Sprite p2Score;
+ p2Score.setPosition(pos(0, 0));
+ makeNum(&p2Score, 0, textures);
+
+ // init piece positions
+ int p_num = (SPRITE_COLS / 2) - (p1->pieces->size() / 2) - 1;
+ for (auto& p : *(p1->pieces)) {
+ p.sprite.setPosition(pos(p_num++, SPRITE_ROWS - 1));
+ }
+
+ p_num = (SPRITE_COLS / 2) - (p2->pieces->size() / 2) - 1;
+ for (auto& p : *(p2->pieces)) {
+ p.sprite.setPosition(pos(p_num++, 0));
+ }
+
+ sf::Sprite roll_result;
+ roll_result.setPosition(pos(12, 4));
+
+ sf::RenderWindow window(sf::VideoMode(SCR_W, SCR_H), TITLE);
+ window.setFramerateLimit(60);
+ window.setVerticalSyncEnabled(true);
+
+ sf::View view(window.getDefaultView());
+ view.zoom(ZOOM);
+ view.setSize(view.getSize() * ZOOM);
+ view.setCenter(view.getSize() / 2.f);
+
+ ur::TimedLatch rolling_animation_timer(sf::seconds(3));
+ ur::TimedLatch rolling_animation_frame_pause_timer(sf::milliseconds(100));
+
+ while (window.isOpen()) {
+
+ sf::Event event;
+ while (window.pollEvent(event)) {
+ if (event.type == sf::Event::Closed ||
+ sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) {
+ window.close();
+ }
+
+ if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) &&
+ !mouse_left_locked) {
+ mouse_left_locked = true;
+ // check rolling button click
+ window.setView(view);
+ auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
+
+ // was roll clicked
+ if (state == GameState::WAITING) {
+ for (auto& s : (*roll_sprites)) {
+ // zoom sprite bounds
+ if (s.getGlobalBounds().contains(mPos)) {
+ std::cout << "Roll!" << std::endl;
+ // setup for rolling
+ rolling_animation_timer.start();
+ change_state(GameState::ROLLING);
+ for (auto& rs : (*roll_sprites)) {
+ rs.setColor(SEMI_TRANSPARENT);
+ }
+ for (int i = 0; i < 8; i++) {
+ (*dice)[i].show = i % 2 == 0; // only show the 0s
+ }
+ break;
+ }
+ }
+ } else if (state == GameState::PLACING) {
+ // is a piece being clicked
+ std::shared_ptr<std::vector<struct piece_t>> pieces;
+ if (p1_turn()) {
+ pieces = p1->pieces;
+ } else {
+ pieces = p2->pieces;
+ }
+
+ for (auto& p : (*pieces)) {
+ if (p.sprite.getGlobalBounds().contains(mPos)) {
+ grabbed_piece = &p;
+ grabbed_piece_origin = grabbed_piece->sprite.getPosition();
+ break;
+ }
+ }
+ }
+ window.setView(window.getDefaultView()); // reset back to main view
+ } else if (!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
+ mouse_left_locked = false;
+ if (state == GameState::PLACING && grabbed_piece != nullptr) {
+ // did the piece drop into place
+ bool in_place = false;
+ sf::FloatRect intersect;
+ for (auto& s : *(board)) {
+ if (s.getGlobalBounds().intersects(
+ grabbed_piece->sprite.getGlobalBounds(), intersect)) {
+ if (intersect.width > SPRITE_SIZE / 2 &&
+ intersect.height > SPRITE_SIZE / 2) {
+ grabbed_piece->sprite.setPosition(s.getPosition());
+ in_place = true;
+ break;
+ }
+ }
+ }
+
+ if (in_place) {
+ next_turn();
+ turn_roll = 0;
+ for (auto& s : (*roll_sprites)) {
+ s.setColor(sf::Color::White);
+ }
+ } else {
+ grabbed_piece->sprite.setPosition(grabbed_piece_origin);
+ }
+ grabbed_piece = nullptr;
+ }
+ }
+ }
+
+ window.clear(BG_COLOR);
+ window.setView(view);
+
+ for (auto s : *(board)) {
+ window.draw(s);
+ }
+
+ auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
+ if (grabbed_piece != nullptr) {
+ float x = mPos.x - (grabbed_piece->sprite.getGlobalBounds().width / 2);
+ float y = mPos.y - (grabbed_piece->sprite.getGlobalBounds().height / 2);
+ grabbed_piece->sprite.setPosition(x, y);
+ }
+ // draw unused pieces
+ for (auto& p : *(p1->pieces)) {
+ window.draw(p.sprite);
+ }
+ for (auto& p : *(p2->pieces)) {
+ window.draw(p.sprite);
+ }
+
+ render_dice(&window,
+ dice,
+ roll_sprites,
+ textures,
+ &roll_result,
+ &rolling_animation_timer,
+ &rolling_animation_frame_pause_timer);
+ for (auto& s : (*roll_sprites)) {
+ window.draw(s);
+ }
+
+ window.draw(p1Score);
+ window.draw(p2Score);
+ window.setView(window.getDefaultView());
+ window.display();
+ }
+
+ return EXIT_SUCCESS;
+}