diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/helper.cpp | 265 | ||||
| -rw-r--r-- | src/helper.hpp | 104 | ||||
| -rw-r--r-- | src/random.cpp | 27 | ||||
| -rw-r--r-- | src/random.hpp | 19 | ||||
| -rw-r--r-- | src/timedLatch.cpp | 38 | ||||
| -rw-r--r-- | src/timedLatch.hpp | 22 | ||||
| -rw-r--r-- | src/ur.cpp | 334 | 
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; +}  |