From 176833bb9af6345734ae5ada88a05fd8c9494ab9 Mon Sep 17 00:00:00 2001 From: Pharap <2933055+Pharap@users.noreply.github.com> Date: Thu, 15 Mar 2018 20:45:33 +0000 Subject: [PATCH] Upload original source files --- Game.h | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++ Grid.h | 94 ++++++++++++ My_settings.h | 18 +++ Point.h | 33 +++++ main.cpp | 30 ++++ 5 files changed, 560 insertions(+) create mode 100644 Game.h create mode 100644 Grid.h create mode 100644 My_settings.h create mode 100644 Point.h create mode 100644 main.cpp diff --git a/Game.h b/Game.h new file mode 100644 index 0000000..98c410c --- /dev/null +++ b/Game.h @@ -0,0 +1,385 @@ +#pragma once + +/* + Copyright (C) 2018 Pharap (@Pharap) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#define DISABLEAVRMIN +#include + +#include + +#include "Grid.h" +#include "Point.h" + +class Game +{ +public: + enum class Status : unsigned char + { + Unfinished, + NoughtsWins, + CrossesWins, + Draw, + }; + + enum class Cell : unsigned char + { + None, + Nought, + Cross, + }; + +public: + using CellGrid = Grid; + using PointType = Point; + +private: + CellGrid grid; + PointType selector; + Cell currentTurn = Cell::Nought; + Status status = Status::Unfinished; + +public: + void run(void); + +private: + void update(void); + void draw(void); + + Status calculateStatus(void) const; +}; + +inline void Game::run(void) +{ + Pokitto::Core::begin(); + + while (Pokitto::Core::isRunning()) + { + if (Pokitto::Core::update()) + { + this->update(); + this->draw(); + } + } +} + +inline Game::Status Game::calculateStatus(void) const +{ + PointType const winningSets[][3] = + { + // Vertical + { PointType(0, 0), PointType(0, 1), PointType(0, 2) }, + { PointType(1, 0), PointType(1, 1), PointType(1, 2) }, + { PointType(2, 0), PointType(2, 1), PointType(2, 2) }, + + // Horizontal + { PointType(0, 0), PointType(1, 0), PointType(2, 0) }, + { PointType(0, 1), PointType(1, 1), PointType(2, 1) }, + { PointType(0, 2), PointType(1, 2), PointType(2, 2) }, + + // Diagonal + { PointType(0, 0), PointType(1, 1), PointType(2, 2) }, + { PointType(2, 0), PointType(1, 1), PointType(0, 2) }, + }; + + for(auto const & line : winningSets) + { + PointType start = line[0]; + Cell type = this->grid.getItem(start.x, start.y); + + if(type == Cell::None) + continue; + + bool success = true; + for(int i = 0; i < 3; ++i) + { + if(this->grid.getItem(line[i].x, line[i].y) != type) + { + success = false; + break; + } + } + + if(success) + { + switch(type) + { + case Cell::Nought: + return Status::NoughtsWins; + case Cell::Cross: + return Status::CrossesWins; + default: + return Status::Unfinished; + } + } + } + + bool hasEmptySpace = false; + for(int y = 0; y < 3 && !hasEmptySpace; ++y) + { + for(int x = 0; x < 3; ++x) + { + if(this->grid.getItem(x, y) == Cell::None) + { + hasEmptySpace = true; + break; + } + } + } + + return hasEmptySpace ? Status::Unfinished : Status::Draw; +} + +inline void Game::update(void) +{ + 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; + } + + 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; + } +} + +inline void Game::draw(void) +{ + // Drawing parameters for easy modification + const int xGap = 8; + const int yGap = 8; + const int cellWidth = 32; + const int cellHeight = 32; + + //const int blackIndex = 0; + const int whiteIndex = 1; + + const int boardWidth = (cellWidth * 3 + xGap * 2); + const int boardHeight = (cellHeight * 3 + yGap * 2); + + const int xOffset = (Pokitto::Display::getWidth() - boardWidth) / 2; + const int yOffset = (Pokitto::Display::getHeight() - boardHeight) / 2; + + const int leftLineX = xOffset + (cellWidth * 1) + (xGap * 0) + (xGap / 2); + const int rightLineX = xOffset + (cellWidth * 2) + (xGap * 1) + (xGap / 2); + + const int topLineY = yOffset + (cellHeight * 1) + (yGap * 0) + (yGap / 2); + const int bottomLineY = yOffset + (cellHeight * 2) + (yGap * 1) + (yGap / 2); + + // Draw lines + Pokitto::Display::setColor(whiteIndex); + + Pokitto::Display::drawLine(leftLineX, yOffset - 4, leftLineX, yOffset + boardHeight + 8); + Pokitto::Display::drawLine(rightLineX, yOffset - 4, rightLineX, yOffset + boardHeight + 8); + + Pokitto::Display::drawLine(xOffset - 4, topLineY, xOffset + boardWidth + 8, topLineY); + Pokitto::Display::drawLine(xOffset - 4, bottomLineY, xOffset + boardWidth + 8, bottomLineY); + + + // 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 symbol + 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::drawRect(cellX, cellY, cellWidth, cellHeight); + } + } + } + + Pokitto::Display::setCursor(16, 8); + switch(this->status) + { + case Status::Unfinished: + { + switch(this->currentTurn) + { + 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; + } + } + break; + } + case Status::NoughtsWins: + { + Pokitto::Display::print("Noughts Wins!"); + break; + } + case Status::CrossesWins: + { + 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); + } + } + } +}*/ diff --git a/Grid.h b/Grid.h new file mode 100644 index 0000000..40f5cbd --- /dev/null +++ b/Grid.h @@ -0,0 +1,94 @@ +#pragma once + +/* + Copyright (C) 2018 Pharap (@Pharap) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +template< typename Type, std::uint8_t WidthValue, std::uint8_t HeightValue > +class Grid +{ +public: + using ValueType = Type; + +public: + constexpr static const std::uint8_t Width = WidthValue; + constexpr static const std::uint8_t Height = HeightValue; + constexpr static const std::uint16_t Count = Width * Height; + +private: + ValueType items[Count]; + + inline std::uint8_t flattenIndex(const std::uint8_t & x, const std::uint8_t & y) const + { + return (Width * y) + x; + } + +public: + constexpr std::uint16_t getCount(void) const; + constexpr std::uint8_t getWidth(void) const; + constexpr std::uint8_t getHeight(void) const; + + ValueType & getItem(const std::uint8_t & x, const std::uint8_t & y); + const ValueType & getItem(const std::uint8_t & x, const std::uint8_t & y) const; + + void fill(const ValueType & value); // O(n) + void clear(void); // O(n) +}; + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +constexpr std::uint16_t Grid::getCount(void) const +{ + return Grid::Count; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +constexpr std::uint8_t Grid::getWidth(void) const +{ + return Grid::Width; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +constexpr std::uint8_t Grid::getHeight(void) const +{ + return Grid::Height; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +typename Grid::ValueType & Grid::getItem(const std::uint8_t & x, const std::uint8_t & y) +{ + return this->items[flattenIndex(x, y)]; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +const typename Grid::ValueType & Grid::getItem(const std::uint8_t & x, const std::uint8_t & y) const +{ + return this->items[flattenIndex(x, y)]; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +void Grid::fill(const ValueType & value) +{ + for(std::uint16_t i = 0; i < Count; ++i) + items[i] = value; +} + +template< typename Type, std::uint8_t Width, std::uint8_t Height > +void Grid::clear(void) // O(n) +{ + for (std::uint16_t i = 0; i < Count; ++i) + (&this->items[i])->~ValueType(); +} diff --git a/My_settings.h b/My_settings.h new file mode 100644 index 0000000..dd1ca7e --- /dev/null +++ b/My_settings.h @@ -0,0 +1,18 @@ +/**************************************************************************/ +/*! + @file My_settings.h + @author XX + + @section HOW TO USE My_settings + + My_settings can be used to set project settings inside the mbed online IDE +*/ +/**************************************************************************/ + +#ifndef MY_SETTINGS_H +#define MY_SETTINGS_H + +#define PROJ_HIRES 1 //1 = high resolution (220x176) , 0 = low resolution fast mode (110x88) +#define PROJ_ENABLE_SOUND 1 // 0 = all sound functions disabled + +#endif diff --git a/Point.h b/Point.h new file mode 100644 index 0000000..379bd6b --- /dev/null +++ b/Point.h @@ -0,0 +1,33 @@ +#pragma once + +/* + Copyright (C) 2018 Pharap (@Pharap) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +template< typename ValueT > +class Point +{ +public: + using ValueType = ValueT; + +public: + ValueType x; + ValueType y; + +public: + Point(void) = default; + Point(ValueType const & x, ValueType const & y) + : x(x), y(y) {} +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b327812 --- /dev/null +++ b/main.cpp @@ -0,0 +1,30 @@ +/* + Copyright (C) 2018 Pharap (@Pharap) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#define DISABLEAVRMIN +#include + +#include "Game.h" + +Game game; + +// The main function +int main() +{ + game.run(); + return 0; +} +