diff --git a/Game.h b/Game.h index 98c410c..6b091b9 100644 --- a/Game.h +++ b/Game.h @@ -20,6 +20,8 @@ #include #include +#include +#include #include "Grid.h" #include "Point.h" @@ -27,6 +29,13 @@ class Game { public: + enum class Cell : unsigned char + { + None, + Nought, + Cross, + }; + enum class Status : unsigned char { Unfinished, @@ -35,16 +44,9 @@ class Game Draw, }; - enum class Cell : unsigned char - { - None, - Nought, - Cross, - }; - public: using CellGrid = Grid; - using PointType = Point; + using PointType = Point; private: CellGrid grid; @@ -59,10 +61,15 @@ class Game void update(void); void draw(void); + std::pair getWinner(void) const; + bool hasAnyEmptyCells(void) const; Status calculateStatus(void) const; + + void drawGrid(void); + void drawStatus(void); }; -inline void Game::run(void) +void Game::run(void) { Pokitto::Core::begin(); @@ -76,9 +83,68 @@ inline void Game::run(void) } } -inline Game::Status Game::calculateStatus(void) const +void Game::update(void) { - PointType const winningSets[][3] = + if(Pokitto::Buttons::held(BTN_LEFT, 1)) + { + if(this->selector.x > CellGrid::FirstX) + --this->selector.x; + } + + if(Pokitto::Buttons::held(BTN_RIGHT, 1)) + { + if(this->selector.x < CellGrid::LastX) + ++this->selector.x; + } + + if(Pokitto::Buttons::held(BTN_UP, 1)) + { + if(this->selector.y > CellGrid::FirstY) + --this->selector.y; + } + + if(Pokitto::Buttons::held(BTN_DOWN, 1)) + { + if(this->selector.y < CellGrid::LastY) + ++this->selector.y; + } + + if(Pokitto::Buttons::held(BTN_A, 1)) + { + if(this->grid.getItem(this->selector.x, this->selector.y) == Cell::None) + { + this->grid.getItem(this->selector.x, this->selector.y) = this->currentTurn; + switch(this->currentTurn) + { + case Cell::Nought: + this->currentTurn = Cell::Cross; + break; + case Cell::Cross: + this->currentTurn = Cell::Nought; + break; + default: break; + } + + this->status = this->calculateStatus(); + } + } + + if(Pokitto::Buttons::held(BTN_B, 10) && this->status != Status::Unfinished) + { + this->grid.fill(Cell::None); + this->status = Status::Unfinished; + } +} + +void Game::draw(void) +{ + drawGrid(); + drawStatus(); +} + +std::pair Game::getWinner(void) const +{ + static const PointType winningSets[][3] = { // Vertical { PointType(0, 0), PointType(0, 1), PointType(0, 2) }, @@ -97,14 +163,14 @@ inline Game::Status Game::calculateStatus(void) const for(auto const & line : winningSets) { - PointType start = line[0]; - Cell type = this->grid.getItem(start.x, start.y); + const PointType start = line[0]; + const Cell type = this->grid.getItem(start.x, start.y); if(type == Cell::None) continue; bool success = true; - for(int i = 0; i < 3; ++i) + for(std::size_t i = 0; i < 3; ++i) { if(this->grid.getItem(line[i].x, line[i].y) != type) { @@ -115,88 +181,59 @@ inline Game::Status Game::calculateStatus(void) const if(success) { - switch(type) - { - case Cell::Nought: - return Status::NoughtsWins; - case Cell::Cross: - return Status::CrossesWins; - default: - return Status::Unfinished; - } + return std::make_pair(true, type); } } - bool hasEmptySpace = false; - for(int y = 0; y < 3 && !hasEmptySpace; ++y) + return std::make_pair(false, Cell::None); +} + +bool Game::hasAnyEmptyCells(void) const +{ + for(std::size_t y = 0; y < CellGrid::Height; ++y) { - for(int x = 0; x < 3; ++x) + for(std::size_t x = 0; x < CellGrid::Width; ++x) { if(this->grid.getItem(x, y) == Cell::None) { - hasEmptySpace = true; - break; + return true; } } } - return hasEmptySpace ? Status::Unfinished : Status::Draw; + return false; } -inline void Game::update(void) +Game::Status Game::calculateStatus(void) const { - if(Pokitto::Buttons::held(BTN_LEFT, 1)) - { - if(this->selector.x > 0) - --this->selector.x; - } - - if(Pokitto::Buttons::held(BTN_RIGHT, 1)) - { - if(this->selector.x < 2) - ++this->selector.x; - } - - if(Pokitto::Buttons::held(BTN_UP, 1)) - { - if(this->selector.y > 0) - --this->selector.y; - } - - if(Pokitto::Buttons::held(BTN_DOWN, 1)) - { - if(this->selector.y < 2) - ++this->selector.y; - } + const auto winner = getWinner(); + const bool success = winner.first; - if(Pokitto::Buttons::held(BTN_A, 1)) + if(success) { - if(this->grid.getItem(this->selector.x, this->selector.y) == Cell::None) + const Cell type = winner.second; + switch(type) { - this->grid.getItem(this->selector.x, this->selector.y) = this->currentTurn; - switch(this->currentTurn) - { - case Cell::Nought: - this->currentTurn = Cell::Cross; - break; - case Cell::Cross: - this->currentTurn = Cell::Nought; - break; - default: break; - } - - this->status = this->calculateStatus(); + case Cell::Nought: + return Status::NoughtsWins; + case Cell::Cross: + return Status::CrossesWins; + default: + return Status::Unfinished; } } - if(Pokitto::Buttons::held(BTN_B, 10) && this->status != Status::Unfinished) + if(this->hasAnyEmptyCells()) { - this->grid.fill(Cell::None); - this->status = Status::Unfinished; + return Status::Unfinished; + } + else + { + return Status::Draw; } } -inline void Game::draw(void) +void Game::drawGrid(void) { // Drawing parameters for easy modification const int xGap = 8; @@ -207,8 +244,8 @@ inline void Game::draw(void) //const int blackIndex = 0; const int whiteIndex = 1; - const int boardWidth = (cellWidth * 3 + xGap * 2); - const int boardHeight = (cellHeight * 3 + yGap * 2); + const int boardWidth = (cellWidth * CellGrid::Width) + (xGap * 2); + const int boardHeight = (cellHeight * CellGrid::Height) + (yGap * 2); const int xOffset = (Pokitto::Display::getWidth() - boardWidth) / 2; const int yOffset = (Pokitto::Display::getHeight() - boardHeight) / 2; @@ -230,9 +267,9 @@ inline void Game::draw(void) // Draw grid - for(int y = 0; y < 3; ++y) + for(std::size_t y = 0; y < CellGrid::Height; ++y) { - for(int x = 0; x < 3; ++x) + for(std::size_t x = 0; x < CellGrid::Width; ++x) { const int cellX = xOffset + ((cellWidth + xGap) * x); const int cellY = yOffset + ((cellHeight + yGap) * y); @@ -241,27 +278,27 @@ inline void Game::draw(void) switch(grid.getItem(x, y)) { case Cell::Nought: - { - const int halfCellWidth = cellWidth / 2; - const int halfCellHeight = cellHeight / 2; - const int cellCentreX = cellX + halfCellWidth; - const int cellCentreY = cellY + halfCellHeight; - const int radius = std::min(halfCellWidth, halfCellHeight) - 1; - - Pokitto::Display::drawCircle(cellCentreX, cellCentreY, radius); - break; - } + { + const int halfCellWidth = cellWidth / 2; + const int halfCellHeight = cellHeight / 2; + const int cellCentreX = cellX + halfCellWidth; + const int cellCentreY = cellY + halfCellHeight; + const int radius = std::min(halfCellWidth, halfCellHeight) - 1; + + Pokitto::Display::drawCircle(cellCentreX, cellCentreY, radius); + break; + } case Cell::Cross: - { - const int left = cellX + 1; - const int top = cellY + 1; - const int right = cellX + cellWidth - 1; - const int bottom = cellY + cellHeight - 1; - - Pokitto::Display::drawLine(left, top, right, bottom); - Pokitto::Display::drawLine(right, top, left, bottom); - break; - } + { + const int left = cellX + 1; + const int top = cellY + 1; + const int right = cellX + cellWidth - 1; + const int bottom = cellY + cellHeight - 1; + + Pokitto::Display::drawLine(left, top, right, bottom); + Pokitto::Display::drawLine(right, top, left, bottom); + break; + } default: break; } @@ -273,113 +310,49 @@ inline void Game::draw(void) } } } +} +void Game::drawStatus(void) +{ Pokitto::Display::setCursor(16, 8); switch(this->status) { case Status::Unfinished: + { + switch(this->currentTurn) { - switch(this->currentTurn) + case Cell::Nought: { - case Cell::Nought: - { - Pokitto::Display::print("Player: Noughts"); - break; - } - case Cell::Cross: - { - Pokitto::Display::print("Player: Crosses"); - break; - } - case Cell::None: - { - Pokitto::Display::print("Error!?"); - break; - } + Pokitto::Display::print("Player: Noughts"); + break; + } + case Cell::Cross: + { + Pokitto::Display::print("Player: Crosses"); + break; + } + case Cell::None: + { + Pokitto::Display::print("Error!?"); + break; } - break; } + break; + } case Status::NoughtsWins: - { - Pokitto::Display::print("Noughts Wins!"); - break; - } + { + Pokitto::Display::print("Noughts Wins!"); + break; + } case Status::CrossesWins: - { - Pokitto::Display::print("Crosses Wins!"); - break; - } + { + Pokitto::Display::print("Crosses Wins!"); + break; + } case Status::Draw: - { - Pokitto::Display::print("Draw!"); - break; - } - } -} - -// Old version -/*inline void Game::draw(void) -{ - // Drawing parameters for easy modification - const int xOffset = 16; - const int yOffset = 16; - const int xGap = 8; - const int yGap = 8; - const int cellWidth = 32; - const int cellHeight = 32; - - const int boxColourIndex = 3; - const int symbolColourIndex = 0; - const int selectorColourIndex = 1; - - // Draw grid - for(int y = 0; y < 3; ++y) - { - for(int x = 0; x < 3; ++x) { - const int cellX = xOffset + ((cellWidth + xGap) * x); - const int cellY = yOffset + ((cellHeight + yGap) * y); - - // Draw box - Pokitto::Display::setColor(boxColourIndex); - Pokitto::Display::fillRect(cellX, cellY, cellWidth, cellHeight); - - // Draw symbol - Pokitto::Display::setColor(symbolColourIndex); - switch(grid.getItem(x, y)) - { - case Cell::Nought: - { - const int halfCellWidth = cellWidth / 2; - const int halfCellHeight = cellHeight / 2; - const int cellCentreX = cellX + halfCellWidth; - const int cellCentreY = cellY + halfCellHeight; - const int radius = std::min(halfCellWidth, halfCellHeight) - 1; - - Pokitto::Display::drawCircle(cellCentreX, cellCentreY, radius); - break; - } - case Cell::Cross: - { - const int left = cellX + 1; - const int top = cellY + 1; - const int right = cellX + cellWidth - 1; - const int bottom = cellY + cellHeight - 1; - - Pokitto::Display::drawLine(left, top, right, bottom); - Pokitto::Display::drawLine(right, top, left, bottom); - break; - } - default: - break; - } - - // Draw selector - if(x == this->selector.x && y == this->selector.y) - { - Pokitto::Display::setColor(selectorColourIndex); - Pokitto::Display::drawRect(cellX, cellY, cellWidth, cellHeight); - } + Pokitto::Display::print("Draw!"); + break; } } -}*/ +} diff --git a/Grid.h b/Grid.h index 40f5cbd..71ccd2c 100644 --- a/Grid.h +++ b/Grid.h @@ -29,6 +29,11 @@ class Grid constexpr static const std::uint8_t Height = HeightValue; constexpr static const std::uint16_t Count = Width * Height; + constexpr static const std::uint8_t FirstX = 0; + constexpr static const std::uint8_t FirstY = 0; + constexpr static const std::uint8_t LastX = Width - 1; + constexpr static const std::uint8_t LastY = Height - 1; + private: ValueType items[Count];