Tic tac toe 4x4 game 2x2 grouping win algorithm - java

Hello I am creating a basic tic tac toe game for my own pleasure that has 4x4 fields I have the program pretty much completed but I am stuck on one part in my game i have to decide a winner if any x's or o's are grouped by 2x2 i already have the horizontal and vertical and diagonal algorithms to decide a winner completed
so for example if we have
x|x|o|o
x|x|o|x
| | |
| | |
X will be the winner since he has a 2x2 group
thank you for any help!
example code for my vertical winner code
public boolean checkForWin()
{
char symbol = SYMBOL[turn];
//check vertical win
Check1:
for(int i=0; i<BOARD_SIZE; i++)
{
for(int j=0; j<BOARD_SIZE; j++)
if(board[i][j] != symbol)
continue Check1;
//if reached, winning line found
return true;
}
//check horizontal win
Check2:
for(int j=0; j<BOARD_SIZE; j++)
{
for(int i=0; i<BOARD_SIZE; i++)
if(board[i][j] != symbol)
continue Check2;
//if reached, winning line found
return true;
}
//check back slash diagonal win q
for(int i=0; i<BOARD_SIZE; i++)
if(board[i][i] != symbol)
break;
else if(i == BOARD_SIZE-1)
return true; // winning line found
//check forward slash diagonal win
for(int i=0; i<BOARD_SIZE; i++)
if(board[i][BOARD_SIZE - i - 1] != symbol)
break;
else if(i == BOARD_SIZE-1)
return true; // winning line found
//if reach here then no win found
return false;
}
where would i input that code ?

Create a list of winning configurations each having 4 locations. There are 4 winning rows, 4 winning columns, 2 diagonals, and 9 blocks. Then just check each configuration.
Code would be roughly
// Set this up once at the start
WinningConfiguration[] allWinningConfigurations = {
WinningConfiguration.row(0),
...
WinningConfiguration.row(3);
WinningConfiguration.column(0);
...
WinningConfiguration.column(3);
WinningConfiguration.block(0,0);
...
WinningConfiguration.block(3,3);
WinningConfiguration.diagonal();
WinningConfiguration.reversedDiagonal();
}
..
// Now all your checks, (row, column, diagonal and blocks) become
for(WinningConfiguration config : allWinningConfigurations) {
boolean configWins = true;
for(int i=0; i<4; ++i) {
if(board[config.pts[i].x][config.pts[i].y]!=symbol) {
configWins = false;
break;
}
}
if(configWins)
return true;
}
return false;
And if you then want to add other winning combinations (say all four corners) you only need to add one row to your winning Configurations array and you're done.
There's further refactoring that could be done to make this neater too, like moving the check into the WinningConfiguration class so that the loop becomes
for(WinningConfiguration config : allWinningConfigurations) {
if(config.wins(symbol)
return true;
}
return false;

Think of it this way: EVERY winning 2x2 square will have a topleft corner. So if you see a mark, you can check to see if the square to the right, bottom, and bottomright are all the same type, and if so, marker that player a winner. Since you're starting your check on the topleft corner, you never need to put a starter check on the rightmost or bottommost lines (because you won't have a square extend outside your board!)
So for int i extending from 0 to BOARD_SIZE-1, and for int j extending from 0 to BOARD_SIZE-1, if board[i][j] == board[i+1][j] == board[i][j+1] == board[i+1][j+1] == symbol then you have yourself a winner.
There are a few things you could do beyond that to make it a bit more efficient, but since it's tic-tac-toe I don't think you're too concerned with scalability =)

Related

How can I check if the first row of a 2D array with no fixed dimension all have the same value?

I'm making a tic tac toe game in Java with a customizable dimension feature (user can choose to play 3x3, 4x4, 5x5, etc.) and was working on the logic regarding finding a winner. Currently I'm trying to figure out checking for wins horizontally.
I've had the idea to make a nested for-loop to check the 2d array that hosts the board, but am not sure how to execute this. The problem with this code:
for (int i = 0; i < dimension; i++) {
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != '-') {
// you won!
}
}
...Is that its logic is fixed for a 3x3 game, not for any other dimensions. I only know how to add values into 2d arrays, so how can I check if these values are equal? Thank you in advance.
I'm not sure about the rules for winning tic tac toe in higher dimensions, so let's say you have to fill the whole row/column to win.
Divide the if in two parts: The check for the first chararacter and the comparisons. Then use a second for-loop for the comparisons, like this:
for (int i = 0; i < dimension; i++) { // iterate rows
// check for first character
if (board[i][0] == '-') { // if wrong character...
continue; // ... check next row
}
boolean won = true;
for (int j = 0; j < dimension - 1; j++) { // iterate columns
if (board[i][j] != board[i][j+1]) { // if other character...
won = false; // ...not winnable with this column and...
break; // ...stop iteration of columns
}
}
if (won) {
// you won!
}
}
If you win with less crosses 'X' in all dimensions, you would have to add a third loop to go through the possible start points or you could count the amount of crosses in the column and reset the number if there is an 'O'.

Creating a Tic-Tac-Toe AI that will override a random selector if it sees a winning move

I have created a working tic-tac-toe engine. So far it supports player vs player, and player vs a very basic AI that selects completely random moves. I would like to add the ability for the AI to continue selecting randomly UNLESS it sees a move that will win the game. I.E. The AI moves randomly until it has 2 in a row with one spot that is empty, and at that point it will choose to play in the winning position.
Here is what I have so far :
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == ' ') {
possibleMove[0] = i;
possibleMove[1] = j;
}
if (board[i][j] == playerAI.moveType) {
winCount++;
if (winCount == 2) {
myMove = possibleMove;
winCount = 0;
System.out.println("row area " + Arrays.toString(myMove));
}
}
}
winCount = 0;
}
My idea is to check every space on the board ^^ this one checks the rows. I will store any possible move the board finds, and then it will up a counter if we have a move in that row already. If the counter hits 2, then we should go to whatever our stored move is.
I have 4 more functions for columns, diagonals, and anti diagonals, that are the exact same principle.
Can someone please help me find where the flaw in my logic is?
Another solution is for each cell to check if its two neighbours are full and it is empty:
public class StackOverflow{
static char[][] board = {{'x', 'x', ' '}, {'x', ' ', ' '}, {' ', ' ', ' '}};
public static int[] checkRow(){
for (int i = 0; i<3; i++){
for (int j = 0; j<3; j++){
if (board[i][(j+1)%3]=='x' && board[i][(j+1)%3]=='x' && board[i][j]==' '){
return new int[]{i, j};
}
}
}
return null;
}
public static void main(String[] args){
System.out.println(checkRow()[0] + " "+checkRow()[1]);
}
}
This will iterate through every cell, and check the ones 1 and 2 to the left, mod 3 so that you never check out of bounds. It returns null on a failed attempt. (which will throw because of the print statement, not because of the function itself)
One issue: If [0,0], [0,1] and [0,2] are all filled, when you reach [0,3] winCount will be 2 but possibleMove won’t have been set in this particular loop. It’ll set myMove to whatever nonsense was there previously e.g. [0,0], which obviously has nothing to do with row 0.
To get around this (for rows) you could reset winCount to 0 and possibleMove to [-1,-1] on each iteration of the outer loop, then you should use the check if (winCount == 2 && possibleMove[0] != -1 && possibleMove[1] != -1) before setting myMove.
Obviously that’s only for rows, for columns/diags you’d need to reset the values slightly differently.

StackOverflow error for maze solving program

Currently I am trying to solve a program that determines whether it is possible to solve a maze and if the maze is solvable it should print out the number of steps to go through the maze path. The starting position and the end position and the maze are given in a input file in the following format:
Line 1: test cases(N)
For each N lines the first line will contain size of the maze, the start position and the end exit location will be given. Then a visual depiction of the maze will also be present in the input file
For example the sample input for this challenge is:
3
6 7 0 0 5 6
1110111
1011101
1001001
1011101
1000001
1111110
3 3 2 0 0 2
111
110
111
5 5 1 0 3 1
01111
11001
01001
01001
01111
The excact rules of the maze are that the 0s are inpenetrable walls and the 1s are free walking space being able to move around. Also the end position is not marked by any special character but rather the location is given to us.
The following code is my approach to the challenge which is obviously not functional:
import java.io.*;
import java.util.*;
public class Maze
{
public static void main(String[] args) throws FileNotFoundException
{
Scanner sc = new Scanner(new File("maze.txt"));
int tc = sc.nextInt();
for(int p = 0; p < tc; p++ ) {
int rows = sc.nextInt();
int cols = sc.nextInt();
int startRow = sc.nextInt();
int startCol = sc.nextInt();
int endRow = sc.nextInt();
int endCol = sc.nextInt();
sc.nextLine();
char[][] maze = new char[rows][cols];
for(int i = 0; i < rows; i++) {
String s = sc.nextLine();
for(int j = 0; j < cols; j++) {
maze[i][j] = s.charAt(j);
}
}
if(solvable(maze,startRow,startCol,endCol,endRow)) {
int count = 0;
for(char[] arr : maze) {
for(char elem: arr) {
if(elem == 'x') count++;
}
}
System.out.println("It takes " + count + " steps to solve the maze");
}else {
System.out.println("Unsolvable");
}
}
}
public static boolean solvable(char[][] maze,int row, int col,int finishRow, int finishCol) {
if(row < 0 || col < 0 || row >maze.length - 1 || col > maze[0].length - 1) {
return false;
}
if(row == finishRow && col == finishCol) {
return true;
}
if(maze[row][col] == 0) {
return false;
}
char c = maze[row][col];
maze[row][col] = 'x';
if(solvable(maze,row + 1,col,finishRow,finishCol)) {
return true;
}
if(solvable(maze,row - 1,col,finishRow,finishCol)){
return true;
}
if(solvable(maze,row ,col + 1,finishRow,finishCol)) {
return true;
}
if(solvable(maze,row,col - 1,finishRow,finishCol)) {
return true;
}
maze[row][col] = c;
return false;
}
}
As seen by the title this program produces a stack overflow error. I am incorporating the general algorithm for solving a maze and not incorporating the flood fill alogorithm. I need to identify the flaw in my recursive method solvable. Please note that this is a competetive programming enviorment so coding from the object oriented side of java would be inconvinient.
The problem is the infinite recursion in solvable. Why is that?
Why it never terminates?
Let's take a closer look at how it works:
return false if the position is invalid
return true if the position is the target
return false if the position is the start
This is a bit strange thing to do, but whatever, let's move on
At this point we know the current position is valid
Save the old value of the current position, and mark it with 'x'
Try to move in all possible directions
Restore the original value of the current position
Where's the flaw in this logic?
When is the marking 'x' used? -> Ha!
If the marking 'x' is not used, what's going to happen? -> Ha!
Imagine this is the maze, and the algorithm always checks the path going down first before checking other directions:
#####
#S E#
# ###
# ###
#####
The algorithm will first go from S until the bottom.
At the bottom there is a way to go up,
so it goes one step up.
There, there is a way to go down, so it goes back down.
And it gets stuck going up and down forever.
So the solution is to use the 'x' markings to avoid exploring the same positions forever.

Horizontal win detection won't detect win on bottom row on connect 4 game

Right now I am creating a connect 4 game in swing. I did not post all the GUI components since it is not important. The game detects horizontal wins for all rows except the bottom row. Here is the code for the win detection.
boolean CheckForWin()
{
for (int row = 1; row < gameBoard.length; row++) //Plus 1 is added to prepare for dimension swap.
{
//Player 1 horizontal count
int max=0;
//Player 2 horrizontal count
int max2=0;
int count_piece=0;
for(int column=1; column<gameBoard.length; column++)
{
// check for horizontal
if(row==6)
{
break;
}
if(count_piece<max || count_piece<max2)
{
count_piece=max;
count_piece=max2;
}
if(gameBoard[row][column]=='r')
{
max++;
}
else
{
max=0;
}
if(gameBoard[row][column]=='b')
{
max2++;
}
else
{
max2=0;
}
if(max==4 || max2==4)
{
return true;
}
// check for vertical
}
}
// check for diagonal up
// check for diagonal down
return false;
}
I'm assuming gameboard is an array of arrays? You are starting rows and columns at 1 in your loops but they are 0 based in java. Do you also not detect a win in the furthest left column?
You should change your loops to for int row = 0;... and for int column = 0...

Randomizing obstacles for a game board

I want to place obstacles on a game board using a random number generator. 5% of the board will have a pit which is defined as "*", but the asterisk will not show unless the players lands in that spot; 10% of the board will be blocked spots indicated as "X"; the remaining 85% will be open spaces shown as "." The game board is a 10x10 array with the letter "P" at the upper left hand corner as the starting point for the player, and a "T" at the bottom right hand corner for the ending (treasure). So far I've got this, and I been watching video tutorials as well as reading to try and put this all together, but still stuck:
import java.util.Scanner;
import java.util.Random;
public class Adventure {
public static void main(String[] args) {
char grid[][]= new char[10][10];
Scanner move = new Scanner(System.in);
System.out.println("Here is the current game board:");
System.out.println("-------------------------------");
for(int i=0; i<grid.length; i++) {
for(int j=0; j<grid.length; j++) {
grid[i][j]='.';
grid[0][0]='P';
grid[9][9]='T';
System.out.print(grid[i][j]);
}
Random obstacle = new Random();
int obstacleNum;
for(int k=1; k<=100; k++) {
obstacleNum = 1+obstacle.nextInt(100);
}
System.out.println("");
}
System.out.printf("Enter your move (U/D/L/R)>");
}
}
Not sure where to go after "obstacleNum = 1+obstacle.nextInt(100);"
If your game board has 100 spots, then it will have 5 pits, 10 blocks, and 85 open spaces.
Choose 15 random numbers from 1 to 100; the first 5 identify the pits, and the next 10 identify the blocks.
Create a list to keep track of the 15 numbers. Each time you choose a random number, check to see if the number is already present to the list. If it is, discard it and choose a different random number. Otherwise add it to the list and continue until you've chosen all 15 numbers.
As for the actual interactivity, here is an outline:
x = 0; //coordinates of player, location of P
y = 0;
To hide the pits, before printing, stick in and if statement:
if(grid[i][j]=='*') {
System.out.println("."); //looks like ordinary land
} else {
System.out.println(grid[i][j]);
}
Now have this run when it receives input (pseudo)
//following if for moving left
if(grid[y][x+1] isn't out of bounds and right key is pressed and grid[y][x+1]!='X') {
grid[y][x] = '.'; //removes current position
x++; //change location
}
//following if for moving right
if(grid[y][x-1] isn't out of bounds and left key is pressed and grid[y][x-1]!='X') {
grid[y][x] = '.'; //removes current position
x--; //change location
}
//following if for moving down
if(grid[y+1][x] isn't out of bounds and down key is pressed and grid[y+1][x]!='X') {
grid[y][x] = '.'; //removes current position
y++; //change location
}
//following if for moving up
if(grid[y-1][x] isn't out of bounds and up key is pressed and grid[y-1][x]!='X') {
grid[y][x] = '.'; //removes current position
y--; //change location
}
if(grid[y][x] == '*') { //when trapped in a pit
System.out.println("You fell in a pit. Game over.");
} else {
grid[y][x] = 'P'; //update grid
}
Do you need a fixed amount of obstacles? You are better off putting the code in your loop that defines your the board:
for(int i=0; i<grid.length; i++) {
for(int j=0; j<grid.length; j++) {
int random = Math.random();
if (random <.05){
grid[i][j]='*';
}else if (random < .15) {
grid[i][j]='X'
}else {
grid[i][j]='.';
}
System.out.print(grid[i][j]);
}
}
grid[0][0]='P';
grid[9][9]='T';
Also you should put the cod just above define P and T outside the loop afterwards as it seems it only needs to be done once.
EDIT: this method will give you a representation of the game board, to cover the *, you can either change the print method to print them as . Or maintain a display grid, as well as the actual grid (eg make 2 grids)

Categories