diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..fc097c27cb5370b131c9f23041b80c444f0b46c3 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,25 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${default}", + "${workspaceFolder}/include", + "${workspaceFolder}/windows/include", + "${workspaceFolder}/windows/include/SDL2", + "${workspaceFolder}/assignment" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.19041.0", + "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..cc7df8a747b70af751f5776c2739471ec8d4d7f0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.ipp": "cpp", + "iostream": "cpp" + } +} \ No newline at end of file diff --git a/assignment/assignment.cpp b/assignment/assignment.cpp index 23e5607c2c9d61ddac0f637a94b584d4b30a553e..32c03b06383965c4c62fbf7f3a15c372835439e8 100644 --- a/assignment/assignment.cpp +++ b/assignment/assignment.cpp @@ -3,21 +3,25 @@ #include <vector> #include <cstring> #include <tuple> +#include <cmath> #include <context.hpp> #include <app.hpp> +#include <board.h> using namespace std; -const int width = 640; -const int height = 480; +#define SIZE 3 + +const int width = 600; +const int height = 600; class MyApp: public uwe::App { -private: + public: MyApp(int width, int height, std::string title); ~MyApp(); - + MyApp(); void begin() override; void update() override; void draw() override; @@ -27,6 +31,36 @@ public: void mouse_pressed(int x, int y, uwe::Button button) override; void mouse_released(int x, int y, uwe::Button button) override; void mouse_moved(int x, int y) override; + + // Functions to draw the X and the O relative to the grid. + void drawX(int row, int col); + void drawO(int row, int col); +private: + // Font decleration + uwe::Font font15_; + Board board; + + // Boolean variables to check if the mouse has been pressed or not + bool b1c = false; + bool b1c2 = false; + + // Integers for the size of the buttons used within the app + int bx = 180; + int by = 420; + int bw = 200; + int bh = 100; + int bx2 = 0; + int by2 = 0; + int bw2 = 600; + int bh2 = 600; + + // Boolean values to track whose turn it is + bool playerTurn = true; + bool legalMove = false; + + // Decleration of gamestate values + int state = 0; + enum GAMESTATE {MENU, BOARD, FINISH}; }; MyApp::MyApp(int width, int height, std::string title) { @@ -39,6 +73,8 @@ MyApp::~MyApp() { void MyApp::begin() { + font15_ = create_font("../assets/fonts/FreeSans.ttf", 24, uwe::Colour::black()); + } void MyApp::update() { @@ -53,19 +89,322 @@ void MyApp::key_pressed(uwe::Scancode scancode, bool repeat) { } } -void MyApp::mouse_pressed(int x, int y, uwe::Button button) { -} - -void MyApp::mouse_released(int x, int y, uwe::Button button) { +void MyApp::mouse_pressed(int x, int y, uwe::Button button) +{ + } - + void MyApp::mouse_moved(int x, int y) { } -void MyApp::draw() { - clear(uwe::Colour::black()); +Board::Board() { clearb(); } ; + +// Function to reset all the tiles within the board back to EMPTY +void Board::clearb() +{ + for(int i=0; i<3; i++) + { + for(int j=0; j<3; j++) + { + m[i][j] = EMPTY; + } + } + takenPlace = 0; +} + +// Returns whether the square selected is empty +bool Board::fieldEmpty(int row, int col) const +{ + if (row >= 0 && row < 3 && col >= 0 && col < 3) + return m[row][col] == EMPTY; + + return false; +} + +//Returns whether the square selected contains an X +bool Board::fieldX(int row, int col) const +{ + if (row >= 0 && row < 3 && col >= 0 && col < 3) + return m[row][col] == PX; + + return false; +} + +//Returns whether the square selected contains an O +bool Board::fieldO(int row, int col) const +{ + if(row >= 0 && row < 3 && col >= 0 && col < 3) + return m[row][col] == PO; + + return false; +} + +void MyApp::drawX(int row, int col) +{ + int fieldW = width / 3; + int fieldH = height / 3; + + //Top left corner to bottom right + draw_line(col * fieldW, row * fieldH + fieldH, + col * fieldW + fieldW, row * fieldH); + + //Top right corner to bottom left + draw_line(col * fieldW, row * fieldH, + col * fieldW + fieldW, row * fieldH + fieldH); +} + +// Function to draw the O +void MyApp::drawO(int row, int col) +{ + int fieldW = width / 3; + int fieldH = height / 3; + + // calculate circle center + int centerX = col * fieldW + (fieldW/2); + int centerY = row * fieldH + (fieldH/2); + + int r = fieldW/2; + + double step = 2*M_PI/30; + int endX = centerX + r; + int endY = centerY; + + for(double angle = 0; angle < 2 * M_PI; angle += step) + { + + int startX = endX; + int startY = endY; + endX = r * cos(angle) + centerX; + endY = r * sin(angle) + centerY; + draw_line(startX, startY, endX, endY); + + } } +// Checks the rows to see wether or not there are 3 of the same values for the rows +bool Board::checkRow() const +{ + if(m[0][0] == m[0][1] && m[0][1] == m[0][2] && !fieldEmpty(0,2)) + return true; + else if(m[1][0] == m[1][1] && m[1][1] == m[1][2] && !fieldEmpty(1,2)) + return true; + else if(m[2][0] == m[2][1] && m[2][1] == m[2][2] && !fieldEmpty(2,2)) + return true; + + return false; +} + +// Checks the rows to see wether or not there are 3 of the same values for the collumns +bool Board::checkCol() const +{ + if(m[0][0] == m[1][0] && m[1][0] == m[2][0] && !fieldEmpty(2,0)) + return true; + else if(m[0][1] == m[1][1] && m[1][1] == m[2][1] && !fieldEmpty(2,1)) + return true; + else if(m[0][2] == m[1][2] && m[1][2] == m[2][2] && !fieldEmpty(2,2)) + return true; + + return false; +} + +// Checks the rows to see wether or not there are 3 of the same values for the diaganols +bool Board::checkDiag() const +{ + if(m[0][0] == m[1][1] && m[1][1] == m[2][2] && !fieldEmpty(2,2)) + return true; + else if(m[0][2] == m[1][1] && m[1][1] == m[2][0] && !fieldEmpty(2,0)) + return true; + + return false; +} + +void MyApp::mouse_released(int x, int y, uwe::Button button) +{ + // Switch case statement to determine variables for buttons + // the user can click to navigate around the game + switch(state) + { + case 0: + bx = 180; + by = 420; + bw = 200; + bh = 100; + break; + + case 1: + bx2 = 0; + by2 = 0; + bw2 = 600; + bh2 = 600; + break; + } + + if (state == MENU && !b1c) + { + if((x > bx && y > by) && (x < (bx + bw) && y < (by + bh))) + { + board.clearb(); + b1c = true; + } + } + + if (state == BOARD && !b1c2) + { + if ((x > bx2 && y > by2) && (x < (bx2 + bw2) && y < (by2 + bh2))) + { + b1c2 = true; + } + } +} + +void MyApp::draw() +{ + if (state == MENU) + { + if (b1c) + { + state = 1; + b1c = false; + clear(uwe::Colour::white()); + for (int i = 0; i < SIZE; i++) + { + for (int j = 0; j < SIZE; j++) + { + set_draw_color(uwe::Colour::black()); + draw_rect((i * width) / 3, (j * height) / 3, width / 3, height / 3); + } + } + } + else + { + //Creates the main menu + clear(uwe::Colour::white()); + draw_font(font15_, "Welcome to TicTacToe", 180, 60); + set_draw_color(uwe::Colour::green()); + draw_rect_fill(180, 420, 240, 120); + draw_font(font15_, "PLAY!", 260, 460); + } + } + + if (state == BOARD) + { + if (playerTurn && b1c2) + { + // Normalises the position of where the user clicked the mouse to the grid + int x, y; + SDL_GetMouseState(&x, &y); + + int row = y/(height/3); + int col = x/(width/3); + + // Checks to see wether or not the place is free + if (board.fieldEmpty(row, col)) + { + // Calls the drawO function to draw the X piece on screen. + drawO(row, col); + // Assigns the correct value to the array for the X Piece + board.m[row][col] = board.PO; + legalMove = true; + b1c2 = false; + // Switches players + playerTurn = !playerTurn; + board.takenPlace++; + // Checks if someone has won yet using pre-defined variables. + if (board.checkCol() == true || board.checkDiag() == true || board.checkRow() == true) + { + state = FINISH; + } + } + } + // + else if(!playerTurn && b1c2) + { + // Normalises the position of where the user clicked the mouse to the grid + int x, y; + SDL_GetMouseState(&x, &y); + + int row = y/(height/3); + int col = x/(width/3); + + // Checks to see wether or not the place is free + if (board.fieldEmpty(row, col)) + { + // Calls the drawX function to draw the X piece on screen. + drawX(row,col); + // Assigns the correct value to the array for the X Piece + board.m[row][col] = board.PX; + legalMove = true; + b1c2 = false; + // Switches players + playerTurn = !playerTurn; + board.takenPlace++; + // Checks if someone has won yet using pre-defined variables. + if (board.checkCol() == true || board.checkDiag() == true || board.checkRow() == true) + { + state = FINISH; + } + } + + } + // checks to see if the move was legal and if there has been more than 9 turns taken + else if (legalMove && board.takenPlace >= 9) + { + state = FINISH; + } + // loop to create game board + else + { + for (int i = 0; i < SIZE; i++) + { + for (int j = 0; j < SIZE; j++) + { + set_draw_color(uwe::Colour::black()); + draw_rect((i * width) / 3, (j * height) / 3, width / 3, height / 3); + } + } + } + } + if (state == FINISH) + { + clear(uwe::Colour::white()); + // Switch case statement that works out wether X or O has won based on the number of turns taken. + switch(board.takenPlace){ + case 5: + draw_font(font15_, "Congratulations, O won", 180, 60); + break; + + case 6: + draw_font(font15_, "Congratulations, X won", 180, 60); + break; + + case 7: + draw_font(font15_, "Congratulations, O won", 180, 60); + break; + + case 8: + draw_font(font15_, "Congratulations, X won", 180, 60); + break; + + case 9: + if (board.checkCol() == true || board.checkDiag() == true || board.checkRow() == true) + { + draw_font(font15_, "Congratulations, O won", 180, 60); + break; + } + else + { + draw_font(font15_, "It was a draw you are both trash", 180, 60); + break; + } + default: + draw_font(font15_, "my spaghetti code broke sorry.", 180, 60); + set_draw_color(uwe::Colour::green()); + + } + } + +} + int main(int argc, char *argv[]) { uwe::App* app = new MyApp{width, height, "Assignment"}; diff --git a/include/board.h b/include/board.h new file mode 100644 index 0000000000000000000000000000000000000000..1f67b44e79a9570a25760224b6e3a84286e54d81 --- /dev/null +++ b/include/board.h @@ -0,0 +1,32 @@ +#ifndef _BOARD_ +#define _BOARD_ + +class Board +{ +public: + // Decleration of the board values + enum BOARD_PIECE {EMPTY, PX, PO}; + + Board(); + + // A function to clear the board + void clearb(); + + // Boolean values to check wether a space is already occupied by either an X or O + bool fieldEmpty(int row, int col) const; + bool fieldX(int row, int col) const; + bool fieldO(int row, int col) const; + + // Stores the board values + BOARD_PIECE m[3][3]; + + // A counter for how many moves have been made so that players can draw + int takenPlace; + + // Checks to decide wether or not someone has won + bool checkRow() const; + bool checkCol() const; + bool checkDiag() const; +}; + +#endif \ No newline at end of file