Arrays, Problem Solving, Software Development

Problem Solving: Xs and Os / Tic-Tac-Toe (Part 2)

Start a new project, I was using IntelliJ for this. The below is my folder structure.

In your GameTest file make 4 tests.

	@Test
	public void completeGameWithWinner_shouldReturnWinnerX() {

	}

	@Test
	public void completeGameWithNoWinner_shouldReturnNoWinner() {
		
	}

	@Test
	public void incompleteGameWithWinner_shouldReturnWinnerX() {
		
	}

	@Test
	public void incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet() {

	}

The tests will instantiate a new multidimensional array. Create the arrays as below. Remember from part 1 that Empty is 0, X is 1 and O is 2 when you’re creating the array.

	@Test
	public void completeGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] completeGameWithWinner = {{1, 1, 1},
				{1, 2, 2},
				{2, 2, 1}};
		//when

		//then

	}

	@Test
	public void completeGameWithNoWinner_shouldReturnNoWinner() {
		//given
		int[][] completeGameWithNoWinner = {{2, 1, 1},
				{1, 1, 2},
				{2, 2, 1}};
		//when
		
		//then

	}

	@Test
	public void incompleteGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] incompleteGameWithWinner = {{1, 2, 0},
				{0, 1, 2},
				{0, 0, 1}};
		//when
		
		//then

	}

	@Test
	public void incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet() {
		//given
		int[][] incompleteGameWithNoWinnerYet = {{1, 2, 0},
				{0, 1, 0},
				{0, 2, 0}};
		//when
		
		//then

	}

This array will be a 3 X 3 and will represent a game state. In our code we want to verify this game state. By verify we mean we want to be able to find out if X has won in this game state, if O has won, if there were no winners, if the game isn’t finished. We’re going to abstract the details of the game state to a new Game object. A new game will be instantiated for all the tests here:

public class GameTest {
	private Game game;

Assign game in each test using its multidimensional array.

	@Test
	public void completeGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] completeGameWithWinner = {{1, 1, 1},
				{1, 2, 2},
				{2, 2, 1}};
		//when
		game = new Game(completeGameWithWinner);
		//then
		
	}

	@Test
	public void completeGameWithNoWinner_shouldReturnNoWinner() {
		//given
		int[][] completeGameWithNoWinner = {{2, 1, 1},
				{1, 1, 2},
				{2, 2, 1}};
		//when
		game = new Game(completeGameWithNoWinner);
		//then
		
	}

	@Test
	public void incompleteGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] incompleteGameWithWinner = {{1, 2, 0},
				{0, 1, 2},
				{0, 0, 1}};
		//when
		game = new Game(incompleteGameWithWinner);
		//then
		
	}

	@Test
	public void incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet() {
		//given
		int[][] incompleteGameWithNoWinnerYet = {{1, 2, 0},
				{0, 1, 0},
				{0, 2, 0}};
		//when
		game = new Game(incompleteGameWithNoWinnerYet);
		//then		
	}

Lastly add in assertion statements comparing the message we will expect back when a game state is verified vs what is actually returned:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class GameTest {
	private Game game;

	@Test
	public void completeGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] completeGameWithWinner = {{1, 1, 1},
				{1, 2, 2},
				{2, 2, 1}};
		//when
		game = new Game(completeGameWithWinner);
		//then
		Assertions.assertEquals("The Winner is X", game.verifyGameState());
	}

	@Test
	public void completeGameWithNoWinner_shouldReturnNoWinner() {
		//given
		int[][] completeGameWithNoWinner = {{2, 1, 1},
				{1, 1, 2},
				{2, 2, 1}};
		//when
		game = new Game(completeGameWithNoWinner);
		//then
		Assertions.assertEquals("No Winner - Game Complete", game.verifyGameState());
	}

	@Test
	public void incompleteGameWithWinner_shouldReturnWinnerX() {
		//given
		int[][] incompleteGameWithWinner = {{1, 2, 0},
				{0, 1, 2},
				{0, 0, 1}};
		//when
		game = new Game(incompleteGameWithWinner);
		//then
		Assertions.assertEquals("The Winner is X", game.verifyGameState());
	}

	@Test
	public void incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet() {
		//given
		int[][] incompleteGameWithNoWinnerYet = {{1, 2, 0},
				{0, 1, 0},
				{0, 2, 0}};
		//when
		game = new Game(incompleteGameWithNoWinnerYet);
		//then
		Assertions.assertEquals("No Winner Yet - Game Incomplete", game.verifyGameState());
	}
}

Leave GameTest, we’re going to populate Game now:

In Game, start by declaring fields (I have named them according to their multidimensional coordinates). As these don’t change once declared they are marked final.

public class Game {	
	private final int x0y0;
	private final int x0y1;
	private final int x0y2;
	private final int x1y0;
	private final int x1y1;
	private final int x1y2;
	private final int x2y0;
	private final int x2y1;
	private final int x2y2;
}

As mentioned in part 1 we use ints in place of chars. Declare and use these as static finals to avoid ‘magic numbers’ creeping into your code.

public class Game {
	private static final int EMPTY_VALUE = 0;
	private static final int X = 1;
	private static final int O = 2;	

	private final int x0y0;
	private final int x0y1;
	private final int x0y2;
	private final int x1y0;
	private final int x1y1;
	private final int x1y2;
	private final int x2y0;
	private final int x2y1;
	private final int x2y2;
}

Add in a constructor for Game. This constructor takes a multidimensional array (our game state) in order to instantiate a new Game. In the constructor we have assigned fields of the current object (indicated by this keyword) to equal corresponding coordinates of the multidimensional array used.

public class Game {
	private static final int EMPTY_VALUE = 0;
	private static final int X = 1;
	private static final int O = 2;

	private final int x0y0;
	private final int x0y1;
	private final int x0y2;
	private final int x1y0;
	private final int x1y1;
	private final int x1y2;
	private final int x2y0;
	private final int x2y1;
	private final int x2y2;

	public Game(int[][] newGameDetails) {
		this.x0y0 = newGameDetails[0][0];
		this.x0y1 = newGameDetails[0][1];
		this.x0y2 = newGameDetails[0][2];
		this.x1y0 = newGameDetails[1][0];
		this.x1y1 = newGameDetails[1][1];
		this.x1y2 = newGameDetails[1][2];
		this.x2y0 = newGameDetails[2][0];
		this.x2y1 = newGameDetails[2][1];
		this.x2y2 = newGameDetails[2][2];
	}
}

Below the constructor we’ve just added, we’re now going to add in our main method of this class – verifyGameState(). All of our other Game methods will be private as they do their work inside the Game class, but verifyGameState() will be public so we can call it from outside.

To start off I’m just going to add in a call to setup(), a new method we’ll use to do some work for us.

	public String verifyGameState() {
		setup();
	}

We’ll need to create a new ArrayList that will be accessible to the whole class (and you’ll need the below imports):

import java.util.ArrayList;
import java.util.List;

public class Game {
	private final List<Integer> gameState = new ArrayList<>();

In the new method setup() we are adding to an ArrayList all of the fields of the Game object. This new ArrayList now contains our game state and is therefore appropriately named gameState. I’ve done this because for some of the manipulations later on, an ArrayList is the most flexible way of working with this information.

	private void setup() {
		gameState.add(x0y0);
		gameState.add(x0y1);
		gameState.add(x0y2);
		gameState.add(x1y0);
		gameState.add(x1y1);
		gameState.add(x1y2);
		gameState.add(x2y0);
		gameState.add(x2y1);
		gameState.add(x2y2);
	}

So next in verifyGameState(), before we start looking for Xs or Os, we’re going to have a fail fast check, so if we are passed a board of the wrong size for example, we find this quickly and don’t waste time on it. Add in the If Else statement below:

	public String verifyGameState() {
		setup();
		if(validateGameState()) {
                
		}else return "Invalid Values";
	}	

Now to add our validation. In this example there is only one check by validateBoardSize() and the result is returned by validateGameState(). These are abstracted like this so as to allow you to add several validation checks and then validateGameState() can return an overall result of whether the game state is valid or not. Add the below code after the setup() method:

	private boolean validateGameState() {
		return validateBoardSize();
	}

	private boolean validateBoardSize() {
		return gameState.size() == REQUIRED_BOARD_SIZE;
	}

Add in REQUIRED_BOARD_SIZE as a new static final:

public class Game {
	private final List<Integer> gameState = new ArrayList<>();

	private static final int EMPTY_VALUE = 0;
	private static final int X = 1;
	private static final int O = 2;
	private static final int REQUIRED_BOARD_SIZE = 9;

Now we’re going to add more to verifyGameState() by creating a new method to do some work, called findWinner(). findWinner() is going to check through the gameState list and find if X or O won. If neither won we’ll get findWinner() to return the EMPTY_VALUE and then we can investigate further.

Add the below calls to findWinner() along with the If Else logic:

	public String verifyGameState() {
		setup();
		if(validateGameState()) {
			if(findWinner() != EMPTY_VALUE) {
				if(findWinner() == X) {
					return "The Winner is X";
				}else if(findWinner() == O) {
					return "The Winner is O";
				}
			}
		}else return "Invalid Values";
	}	

Below validateBoardSize() add in findWinner() below.

	private int findWinner() {

	}
}

Now because there are three different directions a player can win in we’re going to call new methods to do that searching for us. Add in the below new methods under findWinner():

	private boolean findWinnerHorizontal(int xOrO) {

	}

	private boolean findWinnerVertical(int xOrO) {

	}

	private boolean findWinnerDiagonal(int xOrO) {

	}

As above in the 3 new methods we are passing in an int xOrO (as in X or O).

First we’ll look at how it will work with just findWinnerHorizontal() and X. In findWinner() we are going to call findWinnerHorizontal() and pass in X (remember, because these correspond to our static final ints declared at the top the IDE recognizes them as ints). findWinnerHorizontal() will take in its xOrO value (X in this case). It will compare X to the Game fields (the idea is to fail fast again, start by comparing X/O to the fields and then following that see if the fields are equal, as per part 1 if a field is Empty then the horizontal/vertical/diagonal line being checked would never win) . findWinnerHorizontal() will return a boolean as to whether there was a horizontal line found containing all Xs.

	private int findWinner() {
		if(findWinnerHorizontal(X)) {
			return X;
		} else if //....
	}

	private boolean findWinnerHorizontal(int xOrO) {
		return ((xOrO == x0y0 && x0y0 == x0y1 && x0y1  == x0y2)||
				(xOrO == x1y0 && x1y0 == x1y1 && x1y1  == x1y2)||
				(xOrO == x2y0 && x2y0 == x2y1 && x2y1  == x2y2));
	}

Now I’ve filled in the rest of findWinner(), findWinnerHorizontal(), findWinnerVertical() and findWinnerDiagonal(). As mentioned above if findWinner() can’t find a winner it will return EMPTY_VALUE.

	private int findWinner() {
		if(findWinnerHorizontal(X)) {
			return X;
		} else if(findWinnerHorizontal(O)) {
			return O;
		} else if(findWinnerVertical(X)) {
			return X;
		} else if(findWinnerVertical(O)) {
			return O;
		} else if(findWinnerDiagonal(X)) {
			return X;
		} else if(findWinnerDiagonal(O)) {
			return O;
		} else return EMPTY_VALUE;
	}

	private boolean findWinnerHorizontal(int xOrO) {
		return ((xOrO == x0y0 && x0y0 == x0y1 && x0y1  == x0y2)||
				(xOrO == x1y0 && x1y0 == x1y1 && x1y1  == x1y2)||
				(xOrO == x2y0 && x2y0 == x2y1 && x2y1  == x2y2));
	}

	private boolean findWinnerVertical(int xOrO) {
		return ((xOrO == x0y0 && x0y0 == x1y0 && x1y0  == x2y0)||
				(xOrO == x0y1 && x0y1 == x1y1 && x1y1  == x2y1)||
				(xOrO == x0y2 && x0y2 == x1y2 && x1y2  == x2y2));
	}

	private boolean findWinnerDiagonal(int xOrO) {
		return ((xOrO == x0y0 && x0y0 == x1y1 && x1y1  == x2y2)||
				(xOrO == x2y0 && x2y0 == x1y1 && x1y1  == x0y2));
	}

Now, almost complete. Back to verifyGameState(). We need to handle the scenario where there is no winner. Add in a call to checkGameComplete() and the If Else logic:

	public String verifyGameState() {
		setup();
		if(validateGameState()) {
			if(findWinner() != EMPTY_VALUE) {
				if(findWinner() == X) {
					return "The Winner is X";
				}else if(findWinner() == O) {
					return "The Winner is O";
				}
			}
			if (checkGameComplete()) {
				return "No Winner - Game Complete";
			}else {
				return "No Winner Yet - Game Incomplete";
			}
		}else return "Invalid Values";
	}

Add new method checkGameComplete() below findWinnerDiagonal(). This will utilise Streams to go through our gameState list and return a boolean based on whether any EMPTY_VALUE was discovered in the list. If there are none (returns true) – then the game was completed with no winner. If it finds empty values (returns false) – then the game is incomplete.

	private boolean checkGameComplete() {
		return gameState.stream()
				.noneMatch(currentGameMark -> currentGameMark.equals(EMPTY_VALUE));
	}

That’s it! I hope this is helpful, my GitHub is linked below with the problem we’ve just discussed.

Standard
Arrays, Problem Solving, Software Development

Problem Solving: Xs and Os / Tic-Tac-Toe (Part 1)

X’s and Os can be represented as a multidimentional array:

0,00,10,2
1,01,11,2
2,02,12,2

Rather than pass in 9 parameters, make each coordinate a field in a Game object. Instead of using X and O in the program, use integers as this is easier to handle. Account for empty spaces with another integer. Use statics for these values to avoid ‘magic numbers’. A game needs to be passed in a required board of size 9. This required board can include X, O and Empty markers.

Assumptions

Assume we are passed a multidimensional int array (int[][]). Assume the conversion (from Empty to 0, X to 1, O to 2) has been completed in another part of the code. Assume we are passed an int[][] of size 3 x 3. Assume play will continue until there is a winner or until all spaces are used.

States

We are accounting for four states our game can be in – Winner with no Empty Spaces, Winner with Empty Spaces, No Winner with no Empty Spaces, No Winner Yet. As the game can have a Winner and contain Empty Spaces therefore for efficiency check for a Winner first. Thereafter if there’s No Winner check if the game has Empty Spaces. If this is the case the game is in state No Winner Yet.

Ways to win

8 ways to win (diagrams below – X placed in diagram but can be X or O). As the winning horizontal/vertical/diagonal line must have 3 X or O markers to win, to fail fast check the markers against X or O first (variable xOrO used for this). If the marker is Empty that line will not be a winning line.

Tests

I tested the ‘happy path’ –

completeGameWithWinner_shouldReturnWinner

completeGameWithNoWinner_shouldReturnNoWinner

incompleteGameWithWinner_shouldReturnWinner

incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet

More exception handling and tests could be added to check for non-happy path scenarios like if the gameState passed is larger or smaller than 3 X 3, and so forth.

Ways to win – diagrams

Horizontal:

XXX
   
   
   
XXX
   
   
   
XXX

Vertical:

X  
X  
X  
 X 
 X 
 X 
  X
  X
  X

Diagonal:

X  
 X 
  X
  X
 X 
X  

I hope this is helpful, my GitHub is linked below with the problem we’ve just discussed.

In Part 2 I’ll discuss more in detail how to implement the solution discussed above.

Standard
Software Development, Technology

Blockchain in 5 minutes

What is Blockchain?
Blockchain is a special kind of database. Information is stored in blocks, and blocks are linked together in a chain.

Nodes
Blockchain exists on multiple computers, known as nodes. Each node has its own copy of the entire Blockchain.

Decentralized
Blockchain can be implemented in a decentralized way, where no single node has control (for example Bitcoin). There are also private centralized Blockchains.

Sequential
As each block is added to the chain it gets a unique hash code, which includes the code of the previous block. If the block is then altered the hash code will change. This will make any attempted change obvious to other nodes.

Immutable
When information is stored in a Blockchain it is considered immutable, or not easily changed. Each node has its own copy of the whole Blockchain so an altered copy will be disregarded by the other nodes who can cross reference with each other and easily identify the mismatched node.

Bitcoin
The most well known application for Blockchain is in cryptocurrencies such as Bitcoin. This Blockchain has thousands of nodes, as private individuals use their own computers to operate as nodes and participate in processing transactions. The cost to the contributors is an increased electric bill, but they are incentivised as they are paid in Bitcoin for the transactions they process.

Bitcoin might have somewhat of a lawless reputation because users don’t have to provide identification as they would for a bank account. However Bitcoin is also a way to “Bank the Unbanked”. Nearly 2 billion adults don’t have a bank account, with nearly all of these living in developing countries. In these countries economies depend on cash, therefore using Bitcoin is a much safer solution than hiding cash at home. In countries with unstable governments it might not be possible for individuals to get the identification they would need to open a bank account. Bitcoin also provides a stable currency in these countries.

Other applications
There are many other applications that can make use of Blockchain technology. One example is the food industry, who are increasingly using Blockchain to track the journey of food products from farms to shelves. This allows for greater traceability and in the event of contaminated food items the source can be more quickly identified.

Another example is the growing use of smart contracts. In a smart contract Blockchain replaces the traditional human third party. For example, a smart contract could be used by a landlord leasing their property. The smart contract will set out the terms for each party (landlord sends the code for the door, tenant sends deposit). If both parties send in their parts by the due date, the smart contract releases funds to the landlord and the door code to the tenant. If the tenant sent in their deposit but the landlord didn’t send the door code, the smart contract refunds the tenant and so on.

Challenges
Companies leveraging Blockchain will need an efficient algorithm. Bitcoin is estimated to be able to process just 7 transactions/second compared to Visa’s 24,000 (although Blockchain solutions in development have reached 30,000). Another challenge is how to incentivise users to become nodes (unless the Blockchain is privately held and managed).

Advantages
Using Blockchain can make processes cheaper, more accurate and more efficient. Without intermediaries there are no fees, no human error and processing can occur around the clock. It provides a secure record for legal documents and a means of storing wealth for those that can’t get a traditional bank account.

Finally
This year 2021 marks 30 years since the technology was first proposed in 1991. With all of the advantages in leveraging Blockchain we can anticipate it becoming much more widespread in years to come.

That’s it! I hope this is helpful, I’ve also linked a great article by Investopedia with more information.

Standard