Group 11: Noughts + Crosses, By Hadia & Milosz

Want to play a fun classic game? Then tune into Noughts and Crosses, Play the game with your family and friends to see who reigns the Ultimate Master of Noughts and Crosses!

Noughts + Crosses is the classic game with a 9 slot grid, in pairs, each player decides on being either an X or O. In turns the players place their X’s or O’s with the aim to get three X’s or O’s in a row to win. These rows can be vertical, horizontal or diagonal and the first player to get 3 in a row wins! 

AIM: To create a fun and interactive Arduino based version that people can play with their friends and family throughout the year, especially this festive season!

 

Action plan: 

Here is our plan to complete this project within the given time frame. We have allocated the tasks that need to be completed and split them over a realistic time frame to allow us to complete this project successfully.

 

Stage:

Task Description: Name: Status/deadline: 
CONCEPT DEVELOPMENT: Research board games and see how they could be played in two separate locations Hadia  QMUL calendar Week 9 
CONCEPT DEVELOPMENT: List of possible components needed for the game Milosz QMUL calendar Week 9/10
PRODUCTION :  Concept outline, what the final product concept consists of  Hadia QMUL calendar Week 9/10
PRODUCTION :  Defining the Interactivity of design Hadia QMUL calendar Week 9/10
PRODUCTION :  Coding Milosz QMUL calendar Week 10/11
PRODUCTION :  Prototyping  Hadia + Milosz QMUL calendar Week 10/11
PRODUCTION :  Refinements  Milosz QMUL calendar Week 10/11
MANUFACTURING:  Build the circuit on the breadboard Hadia + Milosz QMUL calendar Week 10/11
PRESENTING: Documentation of work (google doc+slides) Hadia Continuous 
PRESENTING: Demonstration of working product  Milosz QMUL calendar Week 11/12

 

Here is a meeting plan which we used to coordinate our meetings over the duration of this project, as well as the Microsoft teams meetings we also consistently communicated our updates through WhatsApp and have had many discussions there.

Meeting plan:
Date:  Hadia:  Milosz: Meeting summary:
Week 9 Research existing products and see if analyse to see if any concept of theirs can be replicated  Make flow chart for coding and then start making functions based on the flow chart 1) Existing products are good but are very basic and promote the basic game concept.

2)create prototypes based on the game idea in the next meeting 

Week 10  Led display prototype. Moving forward with the prototype, rework it to make improvements. Rotating block prototype. Working through more of the code and the necessary functions 1) Existing products are taken into account and finalised that we want to move from the rotating block concept and focus on the LED and button-based model. 

2) starting the basic coding and prototyping the model further to improve it

Week 11 Refining the google doc with all work that has been done fully explained on the page. Make sketches of the casing concept idea and start working on this prototype. Add a logo and also   Working through more of the code and the necessary functions. Also, add this to the doc so that it is clear what functions have been coded and what hasn’t. 1) Start assembling the casing and the breadboard circuit with the Arduino UNO

2)Work on the circuit layout so that all components fit into the breadboards

Week 12 Transferring the Doc content to the blog  Fully commenting the code and testing the casing of the LEDs with the breadboard and Arduino UNO board. 1) Transfer the content from this doc to the blog. Additionally, make the PowerPoint presentation using the information available here for the project presentation and demo. 

2) Assemble the casing and the Arduino UNO with the breadboard circuits and record videos to assist with the user manual assembly etc.

 

 

 

 

Allocation of roles:

Hadia: 

  • Final product design and making
  • Coding
  • Sourcing materials 
  • Blog design and formatting

Milosz: 

  • Final product design and making
  • Coding
  • Sourcing materials 
  • Breadboard construction

WEEK 9 OVERVIEW:

Research:

The game board we create is Noughts and Crosses, the aim of the game is to get three of the same counter in a row, the first person to successfully get 3 in a row wins.

Existing products: We had a look at existing products to see how we can modify this game onto an Arduino board so that it can be played with different indicators for its inputs and outputs.

Product A (1): The game comes with 9 cubes which have the X or O on the sides of the cubes. These cubes are placed in the grid with the player’s side facing forward. This way only 9 cubes are needed. In this version, the number of inputs had been reduced by having more than one input available on only one block.
Product B (2): In this version the game allows the players to play 3 rounds of three in a row and comes with counters which are inserted on top of the 9 pole inserts where values can be placed. This edition essentially is the basic game but with more input blocks available as it is designed so that more than one round is played.

Game ideas/concepts:

There are 18 possible input values that are available, 9 input slots per player. These inputs are arranged on a 3×3 grid. 

Concepts:

#1: Have a grid of 9 LEDs which are colour changing to at least two colours and use these to show the physical “grid” inputs. We could potentially use corresponding buttons for inputs, one button per input value as essentially only 9 values will actually be inputted at most in one gameplay. To show that a value has been inputted into the grid the LED position that has been occupied can turn that colour. This way it is clear to see which value is occupied by which player, also When LED is on you can be certain that a value has been inputted. A sound could also possibly be used to show that value has been chosen or to prompt the player to enter a value. A piezoelectric speaker could be used to generate sounds to indicate when the player has won and play a melody which indicates winning.

#2: A keypad could also be used to type the input value in, this could be done so that in a grid labelled 1,2,3 by A, B, C players can input something similar to ‘C2’ into their keyboard to place their marker on the grid. Output can be shown by a serial monitor confirmation of ‘current inputted value: C2’, or ‘the value you have inputted is C2’. 

#3: A servo motor could be used to rotate blocks to pick either O or X when playing the game. This would require a potentiometer to input the values by turning them which would consequently move the servo drive to the side that the player has chosen. Each block would require a corresponding servo motor and potentiometer to control its position. A piezoelectric speaker could be used to generate sounds to indicate when the player has won and play a melody which indicates winning.

 

Potential components that we could use:

– LEDs –> to indicate positions occupied on the board

– Buttons –> to navigate positions occupied and confirm the selection

– Jump Wires –>to connect all components on the board

– Resistors –> to prevent short circuits

– Arduino UNO board –> to run the code for the game

– Breadboard (potentially 2) –> to build the components onto the circuit

– Piezoelectric speaker –> to generate sounds indicating winning or losing

– Potentiometer –> to control/input values into the grid

– Shift registers –> to extend the number of pins available for the circuit

 

WEEK 10 OVERVIEW:

Storyboard exploring where Noughts + Crosses could be used: This allowed us to get an idea of where our product would be put into practice

Low-fi prototype: The concepts which we decided to take forward to make prototypes for were #1 and #3. 

Concept #1: using LED’s to create a similar 3×3 grid with buttons

This design modifies the marking’s of the X and O into a single LED light slot which changes colour depending on the player which imputed the value. There is also a separate pad which replicates the 3×3 grid but is used to enter the value for the input. This grid has two buttons in each slot, each button corresponding to a player. This mapping visual makes it easy for users to understand where their input is being placed on the gamepad user. This button corresponds to the LED light in that slot and changes colour depending on the player button used to input the value. 

Evaluation: The grid for the input pad is slightly overwhelming as there are a lot of buttons and this could overcomplicate the game. The grid could instead be replaced with two separate grids for each corresponding player so it appears clearer when inputting values. The grid visual that maps the gamepad grid should be kept as this is clear and easy for the user to understand visually. 

Concept #3: Use rotating blocks as shown in the research section

Similar to the research we conducted there was one product which we saw where a cube is used with its sides marked with the possible inputs of the grid. Here we replicated this by making a triangular prism-based grid where you have the option of a blank, an O or an X. These blocks could be controlled with a potentiometer and a servo motor which allows the player to rotate the block to their X or O. The output could be that a sound is played by a piezoelectric speaker that says winner or is a victory sound.

Evaluation: Making the blocks of this rotate would require us to order much more equipment and with the time frame this concept could become much more complex than it needs to be 

Conclusion: 

Making the rotating block concept is a bit impractical given our time constraint, and we will have a lot of issues with debugging. This would also require us to order much more servo motors which although could work well, due to corona will take too long to be delivered. Hence why we have decided to go forth with a concept which works better with the materials we have already been given.  This allows us to create a design idea which we can actually implement and make to complete the task at hand.

Flowchart:

Here is a basic flowchart to show how the game will operate regarding the actual coding of it on Arduino, this is what we have based our code off of.

Coding: 

Code Explanation
void loop() {

  input();

}

// Constantly collects the user input:

void input() {

  // Which button is pressed for row and column:

  int row, column;

  // How many row and column buttons are pressed:

  int rowCounter = 0;

  int columnCounter = 0;

  for (int i = 0; i < 3; i++) {

if (checkRowButton(i)) {

   row = i;

   rowCounter++;

}

if (checkColumnButton(i)) {

   column = i;

   columnCounter++;

}

  }

  // If exactly one of each pressed (=the chosen position is clear) and the player hasn’t move yet:

  if (rowCounter == 1 && columnCounter == 1 && !moved) {

makeMove(row, column);

  }

  // If player has just released both buttons:

  else if (rowCounter == 0 && columnCounter == 0 && moved) {

// Switch player:

currentPlayer = !currentPlayer;

// We only switch player once (without that it would switch every loop player does nothing):

moved = false;

  }

  // Otherwise player’s intention is not clear so we just ignore the input.

}

User input is collected with every call of a ‘loop()’ function. It checks how many and which row/column buttons are pressed.

When it’s exactly one of each we can make a move since we know what position has the player chosen.

 

Most of the time there are no buttons pressed. But, when the variable ‘moved’ is true, once we see no buttons pressed that means they were actually just released after the player’s move and we should switch the player. That’s what the last ‘if’ does while also changing ‘moved’ to false ensuring that the player changes only once before the end of the next move.

Code Explanation
void makeMove(int row, int column) {

  // If the selected field is empty:

  if (board[row][column] == EMPTY) {

// The selected field set to belong to current player:

board[row][column] = currentPlayer;

checkWin(row, column);

// Proper LED set to be lit up:

outputData[currentPlayer][row * 3 + column] = 1;

output();

// That means that when the player releases the buttons we should switch players:

moved = true;

  }

}

If the chosen field is already occupied this function does nothing and the program comes back to checking input repeatedly for a valid one. If it’s not, the chosen field is set to belong to the current player and the function ‘checkWin()’ is called.

The output is prepared and displayed and at the end ‘moved’ set to true. Due to that this function doesn’t get called again (although it could, it would do nothing) and when the player releases the buttons program switches to the other one.

Code Explanation
void checkWin(int row, int column) {

  // Number of fields belonging to the player

  // in {chosen row, chosen column, 1st diagonal, 2nd diagonal}:

  int t[4] = {0, 0, 0, 0};

  for (int i = 0; i < 3; i++) {

if (board[row][i] == currentPlayer) {

   t[0]++;

}

if (board[i][column] == currentPlayer) {

   t[1]++;

}

if (board[i][i] == currentPlayer) {

   t[2]++;

}

if (board[i][2 – i] == currentPlayer) {

   t[3]++;

}

  }

  for (int i = 0; i < 4; i++) {

// If anywhere there are 3 fields occupied:

if (t[i] == 3) {

   win();

}

  }

}

Here is an image illustrating the various outputs that mean that the user has won, a function needs to be created to test if the values inputted fall within any of these arrangements for both X and O:(3)

The part responsible for checking it in our code is the function ‘checkWin()’. It is called every time a player makes a move. What it does is checking for above situations for the current player, except for the rows and columns that don’t contain the most recent player’s choice (We don’t have to check them because nothing has changed there since the last move)

The first one of the ‘for’ loops counts how many fields belong to the current player in each of the four cases we are left with. Then the second loop checks if any of those numbers equals 3. If it does, that means there are 3 fields occupied by the same player in one line and that player wins.

Refinements:

For the casing design, we decided to modify it so that the grid is kept with 2 LEDs of different colours in each available position. We want the casing to conceal most of the breadboard and Arduino UNO, just have the buttons and LEDs visible, we would also like some form of marking to clearly show the grid of the game. We want to use the green and red LED’s to maintain the festive theme although variations of this project can be made with different LED colours to accommodate the user’s preferences. The game is designed so that it can be played by anyone over the ages of 3 (4), as the game instructions are relatively simple and can be understood by even young children as well as the adults and teens. This way this project works for almost all ages.

From this first initial concept shown below here is how we modified this to get to the final version of the game:

#1:

#2 #3 #4 respectively: 

In our final modification we have changed it so that the key features are:

– 3×3 grid 

– In each one of the 9 slots, there are pairs of LED’s in a different colour, this should result in 9 LEDs of each colour being used

-Instead of the typical ‘X’ and ‘O’ symbols, different colour LEDs will be used to mark the input on the grid

-The casing will also have 6 buttons which go 3 horizontally and 3 vertically

-These will allow the player to input their values as if they were inputting coordinates (this is a little bit similar to #2 of our initial concept ideas in week 9)

-A effects will be displayed on the LEDs to indicate winning

 

Build the circuit on a breadboard :

For the casing of the game, it will be made so that visually the players can see the 18 LED lights and also the 6 buttons replicate a simple 2D axis, meaning that there are 3 horizontal input buttons and 3 vertical input buttons. These coordinate to their respective positions on the gameboard 3×3 grid shown in the classic game. 

 

WEEK 11 OVERVIEW:

Logo for the game:

We started off by working on a basic X and O and then drew this in a 3D font with Noughts + Crosses printed beneath. We then modified this to add shadowing to the X and O and also a pale yellow fill in colour. This was then further modified with a chain od LED lights being draped around the X and O in the respective colours used in the game. The Noughts + Crosses was drawn in a slightly cursive font beneath the X and O covered in a string of LEDs to form the final logo for our projects.

The final design for the casing:

For the casing of this product we aim to create a shell-like cover which can be placed on top of the breadboards and Arduino UNO, this cover will make the game more aesthetically pleasing through hiding the wiring and other components. We aim to do this through using a 3mm thick  MDF sheet cut to 120mmx200mm. We will then paint the 3×3 grid onto this sheet and add labels for the buttons and the players for each LED. In each of the grid slots, we aim to drill two holes with a 5mm diameter, 3mm apart to insert the LEDs into. Additionally, we will insert  2mm holes going down one vertical side and one horizontal side spaced 5mm apart for the buttons used to input values onto the 3×3 grid. We plan to translate the final idea with 2 LEDs per slot available in the 3×3 grid to the casing. We will also add our logo onto the casing to mark the game with the brand and maintain this logo throughout. The buttons and LEDs will be inserted so visually we can see the buttons and LEDs clearly with the labelling minus the wiring of everything beneath.

Evaluation:

When building the circuit we attempted to make a casing for the circuit to clarify the board and the buttons for the user and also to conceal the unpleasant visual of all the wiring to the breadboard. However due to the use of such a large amount of wires we struggled to create a casing that would actually display the LEDs and buttons without showing any of the other components. 

As you can see in the images it is quite a number of wires that we had to put together and despite trying to divide the casing into separate parts for each section of the buttons as well as the 3×3 LEDs grid we were unable to make a neat and effective casing.

WEEK 12 OVERVIEW:

Video for the intro:

Video for  gameplay:

Video for the green player winning:

Video for the red player winning:

images of the final breadboard and Arduino UNO board:

Creating the guide:

Make an instruction manual explaining how the original game is played and how the original game is played on the new board. This will require step by step images of the components being built onto the breadboard and how they are also connected to the Arduino UNO.

Final maker guide and manual plan:

Components list:

  • Jump Wires (a lot)
  • 18 LEDs
  • 6 buttons 
  • 18 resistors (560 Ohms)
  • Arduino UNO
  • 2 shift registers
  • 2 Breadboards (min 80x60x9mm in size)

Instructions for ‘Noughts + Crosses’ setup: 

  1. Gather all the equipment listed in the tools and equipment list and position it accordingly on top of the two breadboards and Arduino UNO
  2. Once all the components have been placed take the 2 casings made and position the larger casing so that it sits on the LEDs and the smaller casing so that it sits on the buttons. Your setup should appear as shown in image X. 
  3. Open Arduino onto a Windows, Macintosh OSX, or Linux operating system and copy and paste the code provided below.
  4. Once the code has been pasted, verify the code and then upload it onto the Arduino UNO. 
  5. Plugin your Arduino UNO board and see if the starting game visual begins

Instructions for gameplay:

  1. To input a value into the 3×3 grid press the corresponding horizontal and vertical button in the row of the value to select the value. 
  2. Once a value has been inputted by pressing both buttons, let the other player input their value 
  3. Take turns in inputting values until someone wins
  4. When you have won you will the see the winning LED display 

We took this final plan and created a separate PDF maker manual which can be found https://docs.google.com/document/d/1abFGVM4h3Wgejop4499Okkbl8kZb9f4wo10lsa8bUZQ/edit?usp=sharing

Here are also images of the first 4 pages, which were then followed by the code as shown:

Code (paste into Arduino IDE):

// Row and column buttons, it could have been one array but we won’t have enough digital pins,

// so column ones have to be attached to analog pins:

const int ROW_BUTTON_PIN[3] = {11, 12, 13};

const int COLUMN_BUTTON_PIN[3] = {5, 4, 3};

 

// Thats for the two shift registers we have to use,

// first 8 of 9 LEDs in every colour are operated by them:

const int DATA_PIN[2] = {4, 7};

const int LATCH_PIN[2] = {5, 8};

const int CLOCK_PIN[2] = {6, 9};

 

// 9th LED of every colour pinned directly to the Arduino:

const int LED_PIN[2] = {2, 3};

 

// Board data [row][coloumn]:

// 0 – 1st player

// 1 – 2nd player

// 2 – empty

int board[3][3];

 

// When no player has chosen the field yet:

const int EMPTY = 2;

 

// Current player number (0 || 1) and if they moved already in this round:

bool currentPlayer;

bool moved = false;

int moves;

 

// LED states:

bool outputData[2][9];

 

bool won = false;

 

// Constantly collects the user input:

void input() {

 

  // Which button is pressed for row and column:

  int row = 0;

  int column = 0;

 

  // How many row and column buttons are pressed:

  int rowCounter = 0;

  int columnCounter = 0;

 

  for (int i = 0; i < 3; i++) {

    if (checkRowButton(i)) {

      row = i;

      rowCounter++;

    }

    if (checkColumnButton(i)) {

      column = i;

      columnCounter++;

    }

  }

 

  // If exactly one of each pressed (=the chosen position is clear) and the player hasn’t move yet:

  if (rowCounter == 1 && columnCounter == 1 && !moved) {

    makeMove(row, column);

  }

 

  // If player has just released both buttons:

  else if (rowCounter == 0 && columnCounter == 0 && moved) {

 

    if (won) {

      win();

    }

 

    // Switch player:

    currentPlayer = !currentPlayer;

 

    // We only switch player once (without that it would switch every loop player does nothing):

    moved = false;

 

    Serial.println(“switched”);

 

    if (moves == 9) {

      intro();

    }

  }

 

  // Otherwise player’s intention is not clear so we just ignore the input.

}

 

bool checkRowButton(int n) {

  return !(digitalRead(ROW_BUTTON_PIN[n]));

}

 

bool checkColumnButton(int n) {

  return !(analogRead(COLUMN_BUTTON_PIN[n]) / 512);

}

 

void makeMove(int row, int column) {

 

  // If the selected field is empty:

  if (board[row][column] == EMPTY) {

 

    // The selected field set to belong to current player:

    board[row][column] = currentPlayer;

 

    // Proper LED set to be lit up:

    outputData[currentPlayer][row * 3 + column] = 1;

    output();

 

    // That means that when the player releases the buttons we should switch players:

    moved = true;

    moves++;

 

    Serial.println(“moved”);

    checkWin(row, column);

  }

}

 

void checkWin(int row, int column) {

  // Number of fields belonging to the player

  // in {chosen row, chosen column, 1st diagonal, 2nd diagonal}:

  int t[4] = {0, 0, 0, 0};

 

  for (int i = 0; i < 3; i++) {

    if (board[row][i] == currentPlayer) {

      t[0]++;

    }

    if (board[i][column] == currentPlayer) {

      t[1]++;

    }

    if (board[i][i] == currentPlayer) {

      t[2]++;

    }

    if (board[i][2 – i] == currentPlayer) {

      t[3]++;

    }

  }

 

  for (int i = 0; i < 4; i++) {

 

    // If anywhere there are 3 fields:

    if (t[i] == 3) {

      won = true;

    }

  }

}

 

void intro() {

  while (true) {

    reset();

 

    // Animate blinking every next LED:

    for (int i = 0; i < 9; i++) {

 

      outputData[currentPlayer][i] = true;

      output();

 

      if (wait(100)) {

        return;

      }

    }

    for (int i = 0; i < 9; i++) {

 

      outputData[currentPlayer][i] = false;

      output();

 

      if (wait(100)) {

        return;

      }

    }

 

    currentPlayer = !currentPlayer;

  }

}

 

void win() {

  // That’s only for the visual effect:

  // 0 – odd LEDs lit up

  // 1 – even LEDs lit up

  bool x = 0;

 

  reset();

 

  while (true) {

 

    // Animate blinking every other LED:

    for (int i = 0; i < 9; i++) {

      outputData[currentPlayer][i] = (i + x) & 1;

    }

 

    output();

 

    if (wait(420)) {

      return;

    }

 

    x = !x;

  }

}

 

bool wait (int ms) {

  for (int i = 0; i < 100; i++) {

    for (int j = 0; j < 3; j++) {

 

      // If any buttons pressed:

      if (checkRowButton(j) || checkColumnButton(j)) {

        reset();

        return true;

      }

    }

    delay(1);

  }

  return false;

}

 

// Display what is to display:

void output() {

  updateRegister(0);

  updateRegister(1);

  updatePins();

}

 

// Last LED of every colour:

void updatePins() {

  setState(LED_PIN[0], outputData[0][8]);

  setState(LED_PIN[1], outputData[1][8]);

}

 

// First 8 LEDs of every colour:

void updateRegister(bool which) {

  digitalWrite(LATCH_PIN[which], LOW);

 

  for (int i = 7; i >= 0; i–) {

    registerPush(which, outputData[which][i]);

  }

 

  digitalWrite(LATCH_PIN[which], HIGH);

}

 

// Send one bit to the register:

void registerPush(bool which, bool state) {

  setState(DATA_PIN[which], state);

 

  digitalWrite(CLOCK_PIN[which], HIGH);

  delay(1);

  digitalWrite(CLOCK_PIN[which], LOW);

}

 

// Sets proper state of the pin:

void setState(int pin, bool state) {

  if (state) {

    digitalWrite(pin, HIGH);

  } else {

    digitalWrite(pin, LOW);

  }

}

 

void setup() {

  Serial.begin(9600);

 

  pinMode(A5, INPUT_PULLUP);

  pinMode(A4, INPUT_PULLUP);

  pinMode(A3, INPUT_PULLUP);

 

  for (int i = 0; i < 3; i++) {

    pinMode(ROW_BUTTON_PIN[i], INPUT_PULLUP);

  }

 

  for (int i = 0; i < 2; i++) {

    pinMode(DATA_PIN[i], OUTPUT);

    pinMode(LATCH_PIN[i], OUTPUT);

    pinMode(CLOCK_PIN[i], OUTPUT);

 

    pinMode(LED_PIN[i], OUTPUT);

  }

 

  intro();

}

 

void loop() {

  input();

}

 

void reset() {

  won = false;

  moves = 0;

 

  // Empty the board:

  for (int i = 0; i < 3; i++) {

    for (int j = 0; j < 3; j++) {

      board[i][j] = EMPTY;

    }

  }

 

  // Empty the output:

  for (int i = 0; i < 2; i++) {

    for (int j = 0; j < 9; j++) {

      outputData[i][j] = 0;

    }

  }

 

  output();

}

 

References:

(1) https://www.woodentoyshop.co.uk/mini-noughts-and-Crosses.html?gclid=CjwKCAiAiML-BRAAEiwAuWVggsGgtpK02LFgrmwNQgt7nhalLcO-nPZT2z5W645wU0dXq21lzC0I3hoC1R4QAvD_BwE
(2) https://www.jaqueslondon.co.uk/products/noughts-and-Crosses-3d-travel?variant=17233067147353&currency=GBP&utm_medium=product_sync&utm_source=google&utm_content=sag_organic&utm_campaign=sag_organic&gclid=CjwKCAiAiML-BRAAEiwAuWVgghZIziHqdHl8Rj5Bmt6P1NKJoQTT0rKcaqDMZQz6QgJS1RpS1i7VSBoCqe4QAvD_BwE
(3) https://lemmoscripts.com/wp/2018/09/03/creating-a-simple-tic-tac-toe-or-naughts-and-crosses-game-in-javascript-and-jquery/
(4) https://regentsctr.uni.edu/ceestem/resources/game/tic-tac-toe#:~:text=Children%20as%20young%20as%203,competitive%20nature%20of%20the%20game.

Leave a Reply