simplest MiniMax algorithm for TicTacToe AI in Java - java

I was trying to get a grasp of MiniMax algorithm, and have read up on it. My initial approach was to implement a simple MiniMax algorithm, and then to add alpha-beta pruning. However this is my current code:
public int miniMax(char[] node, int playerNum)
{
int victor = checkWin(node); // returns 0 if game is ongoing, 1 for p1, 2 for p2, 3 for tie.
if(victor != 0) //game over .
return score(victor);
if(playerNum == 2) //AI
{
int bestVal = Integer.MIN_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 1);
if(value > bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
else
{
int bestVal = Integer.MAX_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 2);
if(value < bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
}
And my score function
private int Score(int gameState)
{
if(gameState ==2) //O wins.
return 10;
else if(gameState==1) //X wins
return -10;
return 0;
}
Now, I have a working AI that tries to block my move and win, however sometimes it is making non-intelligent choices for instance this is the output I get if my input read from console is 6,7,8 in that order. It does not attempt to block my win. But in other cases it does.
| O | O | |
| | | |
| X | X | X |
In my second attempt I tried 4,3 and it blocked my winning move.
| | O | |
| X | X | O |
| | | |
I was wondering anyone could point out what is wrong with my implementation?

The behavior of the code for the shown examples is correct!
So why is the threat in the following position not blocked? Why does the program play move 1 instead of 6?
O . . O 1 2
. . . numbering available moves: 3 4 5
X X . X X 6
It is because if the game is lost on perfect play the program just plays the first available move.
The algorithm only cares about win or loss and not in how many moves.
See what happens if the threat is blocked:
O . . O . .
. . . . X . and X wins on his next move
X X O X X O

Related

While loop gets terminated before condition is met when backtracking

I'm trying to write an iterative program that will help me palce 4 queens on a 4x4 board without them hitting each other. The problem is after looping through each position and backtracking a couple of times my main while loop that keeps looping until a solution is found gets terminated and the program ends even though the condition is not yet met.
I tried the following code:
static int[] solve(char[][] board){
int[] position = new int[4];
int row = 0;
int column = 0;
while(row < 4){
for(boolean check; column < board.length; column++){
System.out.println("["+row+","+column+"]");
check = true;
for(int queen= 0; queen < row; queen++){
if (position[queen] == column || queen- position[queen] == row - column || queen + position[queen] == row + column) {
check = false;
break;
}
}
if(check){
position[row] = column;
column = 0;
row++;
}
if(column > 2){
column = position[--row];
}
}
}
return position;
}
I'm currently getting the following output:
| Q | X | X | X |
| X | X | X | Q |
| X | Q | X | X |
| Q | X | X | X |
To check when exactly the while loop is getting terminated I printed the location (row and column)
System.out.println("["+row+","+column+"]"); and got the following:
[0,0][1,0][1,1][1,2][2,0][2,1][2,2][2,3][1,3][2,0][2,1][3,0][3,1][3,2][3,3][2,2][2,3]
After backtracking to [2,3] the while loop ends even though my row count is still less than 4.
I was expecting the following output:
| X | Q | X | X |
| X | X | X | Q |
| Q | X | X | X |
| X | X | Q | X |
I tried the code in a different compiler and still got the same wrong output. Is there a logical mistake that I missed out?
I'm new to programming so I'm still trying to get the hang of the fundamentals.

How can I solve java.lang.ArrayIndexOutOfBoundsException error in Java

I'm solving a challenge about making an algorithm.
There is a game of land.
The Land of Landing game consists of 4 rows in total N rows, with scores in all the columns.
When stepping down from the first row, down one row, you must step down on one of the four squares of each row.
However, there is a special rule that can not be repeated in the same row when landing one row at a time.
For example,
| 1 | 2 | 3 | 5 |
| 5 | 6 | 7 | 8 |
| 4 | 3 | 2 | 1 |
If you have stepped on line 1 through line 4 (5), you can not step on line 4 (8) on line 2.
I was trying to use Dynamic Programming in Java.
import java.lang.Math;
import java.util.*;
class Solution {
int [][] dp = new int[100001][4];
int solution(int[][] land) {
int r = land.length;
for (int i = 0; i < 4; i++)
{
dp[0][i] = land[0][i];
}
for (int i = 0; i <r; i++)
{
for (int j = 0; j < 4; ++j)
{
for(int k = 0; k < 4; ++k)
{
if (j != k)
{
dp[i][j] = Math.max(dp[i][j], land[i][j] + dp[i-1][k]);
}
}
}
}
int ans = 0;
for (int i = 0; i < 4; ++i)
{
ans = Math.max(ans, dp[r-1][i]);
}
return ans;
}
}
it shows error
java.lang.ArrayIndexOutOfBoundsException: -1
I was thinking that it was probably something wrong with the Conditional statement.
In C++, these conditional statements are right. It's running perfect. Why am I getting an error in Java? Is there any difference using array between Java and C++?
Can you please tell me how can I solve this error?
dp[i-1][k] - i starts from ZERO in upper loop, so results of this expression becomes -1 as index.
Java array index starts from ZERO, not -1, which is why ArrayIndexOutOfBoundsException.
I don't know the business case, but one way to solve this is, start first for loop from 1 instead 0.

Cover "Manhattan skyline" using the minimum number of rectangles

I write to solve a Codility problem provided below,
You are going to build a stone wall. The wall should be straight and N meters long, and its thickness should be constant; however, it should have different heights in different places. The height of the wall is specified by an array H of N positive integers. H[I] is the height of the wall from I to I+1 meters to the right of its left end. In particular, H[0] is the height of the wall's left end and H[N−1] is the height of the wall's right end.
The wall should be built of cuboid stone blocks (that is, all sides of such blocks are rectangular). Your task is to compute the minimum number of blocks needed to build the wall.
Write a function:
class Solution { public int solution(int[] H); }
that, given an array H of N positive integers specifying the height of the wall, returns the minimum number of blocks needed to build it.
For example, given array H containing N = 9 integers:
H[0] = 8 H[1] = 8 H[2] = 5
H[3] = 7 H[4] = 9 H[5] = 8
H[6] = 7 H[7] = 4 H[8] = 8
the function should return 7. The figure shows one possible arrangement of seven blocks.
Assume that:
N is an integer within the range [1..100,000];
each element of array H is an integer within the range [1..1,000,000,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments).
I write a solution for the provided problem. The algorithm and code is provided below,
Algorithm
i. set block count = 1 and start iterating from the 2nd element of the array
ii. if the current depth is same as previous, keep going
iii. If the current depth is higher, push that in the stack and increase the count
iv. If the current depth is lower, keep poping till the current depth >= peek. Afterward, if the stack size = 0 or higher, increase the block count by 1
The code,
public static int solution(int[] H) {
Stack<Integer> stack = new Stack<>();
stack.push(H[0]);
int count = 1;
int N = H.length;
for (int i = 1; i < N; i++) {
if (H[i] == stack.peek()) {
continue;
} else if (H[i] > stack.peek()) {
stack.push(H[i]);
count++;
} else {
while (!stack.isEmpty() && H[i] < stack.peek()) {
stack.pop();
}
stack.push(H[i]);
count++;
}
}
return count;
}
The solution doesn't provide the correct answer and I can't find the bug even after spending some time in debugging. Can anyone see that?
The test set is provided below and the answer is 7 (I get 8).
int[] H = new int[9];
H[0] = 8;
H[1] = 8;
H[2] = 5;
H[3] = 7;
H[4] = 9;
H[5] = 8;
H[6] = 7;
H[7] = 4;
H[8] = 8;
Thank you.
Python Solution
Here is my solution
Solution with steps details
Codility python 100%
def solution(H):
"""
Codility 100%
https://app.codility.com/demo/results/trainingQKD6JP-PHA/
Idea is to use stack concept
Compute the minimum number of blocks needed to build the wall.
To build the wall start taking blocks of height one by one.
We need to take care of -
- the blocked should not be used again
- this is done only up to blocks height is greater than current
- why we are using last 8 height block if there is already 8 height block used in previous step?
reason is 8 is not present in stack top
8,
8,----- can not use because on stack top 8 is already there
5,
7,
9,
8,
7,------ can not use because on stack top 7 is already there
4,
8,
This is just example with height, see steps of output for details
skip8 skip7
| |
| | | |
| | | | |
| | | | |
| | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
Used blocks-
8
5
7
9
8
4
8
"""
block_count = 0
# stack is used to hold height used to building and remove all the blocks from it,
# if any of the block of stack is greater than current block(to be added for building)
stack = []
for height in H:
print(" ")
print("Current Height " + str(height))
print("Current stack " + str(stack))
# Remove all blocks that are bigger than current height, stack should not be empty
while stack and stack[-1] > height:
stack.pop()
print("After remove bigger blocks than current height " + str(stack))
# stack is not empty and top item of stack is equal to current height
if stack and stack[-1] == height:
# Already used this size of block
print("Already used this size of block " + str(height))
continue
else:
# new block is required, push it's size to the stack
block_count += 1
stack.append(height)
print("Add this block.... " + str(height) + " Minimum Blocks " + str(block_count))
return block_count
Another one in Java. Simpler, because I used assumption that height > 0.
public int solution(int[] hs) {
int squares = 0;
Stack<Integer> s = new Stack<>();
s.push(0);
for (int h: hs) {
while (s.peek() > h) {
s.pop();
}
if (s.peek() != h) {
s.push(h);
++squares;
}
}
return squares;
}
I find the bug and though it may be good to share. The reason is the new height is lesser than the peek value, we will keep popping the entities. So if the stack is not empty, the new height will be the same or higher than the stack peeks value.
If the new height will be the same, it means we already add a block for the height and will not add a new block. A condition is needed for the situation,
if (!stack.isEmpty() && H[i] == stack.peek()) {
continue;
}
The code is provided below provides 100% score,
public int solution(int[] H) {
Stack<Integer> stack = new Stack<>();
stack.push(H[0]);
int count = 1;
int N = H.length;
for (int i = 1; i < N; i++) {
if (H[i] == stack.peek()) {
continue;
} else if (H[i] > stack.peek()) {
stack.push(H[i]);
count++;
} else {
while (!stack.isEmpty() && H[i] < stack.peek()) {
stack.pop();
}
/*
* the new entity is either in same elevation or higher
* */
/*
* if in same elevation, we already added the block, so keep iterating
* */
if (!stack.isEmpty() && H[i] == stack.peek()) {
continue;
}
stack.push(H[i]);
count++;
}
}
return count;
}
If someone is still interested in this exercise, I share my Python solution (100% in Codility)
def solution(H):
stack, count = [], 1
for i in H:
if stack:
if i == stack[-1]:
continue
if i < stack[-1]:
while stack and stack[-1] > i:
stack.pop()
if stack:
if i > stack[-1]:
count+=1
stack.append(i)
else:
count+=1
stack.append(i)
else:
stack.append(i)
return count
Ruby 100%
def solution(h)
h.inject([1, [h.first]]) do |(blocks, stack), n|
next [blocks+1, stack.push(n)] if stack.last < n
stack.pop while stack.any? && stack.last > n
next [blocks, stack] if stack.last == n
[blocks+1, stack.push(n)]
end.first
end
A simpler java solution.
public int solution(int[] H) {
//block count
int count = 0;
// stack is used to hold height used to building and remove all the blocks from it,
// if any of the block of stack is greater than current block(is to be added for building)
Deque<Integer> stack = new ArrayDeque<>();
for (int a : H) {
// Remove all blocks that are bigger than current height, stack should not be empty
while (!stack.isEmpty() && a < stack.peek()) {
stack.pop();
}
//new block is required, push it's size to the stack
if (stack.isEmpty() || a > stack.peek()) {
count++;
stack.push(a);
}
}
return count;
}
My 100% JavaScript solution with O(N) time complexity:
function solution(H) {
let numBlocks = 0;
const blocksHeights = [0];
for (const height of H) {
while (blocksHeights[blocksHeights.length - 1] > height) {
blocksHeights.pop();
}
if (blocksHeights[blocksHeights.length - 1] !== height) {
blocksHeights.push(height);
numBlocks++;
}
}
return numBlocks;
}
in c# (100% in Codility)
public int solution(int[] H) {
Stack<int> stack = new Stack<int>();
stack.Push(H[0]);
int count = 1;
for (int i = 1; i < H.Length; i++)
{
if (H[i] == stack.Peek())
{
continue;
}
else if (H[i] > stack.Peek())
{
stack.Push(H[i]);
count++;
}
else
{
while (!(stack.Count==0) && H[i] < stack.Peek())
{
stack.Pop();
}
if (!(stack.Count==0) && H[i] == stack.Peek()) {
continue;
}
stack.Push(H[i]);
count++;
}
}
return count;
}
100% C++ in Codility
#include <stack>
int solution(vector<int> &H) {
int cnt{0};
std::stack<int> reusedStone;
for (auto h : H) {
if (reusedStone.empty() || (h > reusedStone.top())) {
reusedStone.push(h); cnt++;
} else if (h < reusedStone.top()) {
while ((!reusedStone.empty()) && (h < reusedStone.top())) {
reusedStone.pop();
}
if ((!reusedStone.empty()) && (h == reusedStone.top())) {
continue;
} else {
reusedStone.push(h); cnt++;
}
}
}
return cnt;
}
My python solution (100% success rate on Codility)
import math
def solution(H):
nb_blocks = 0
horizon = [math.inf]
for h in H:
while horizon and h < horizon[-1]:
horizon.pop()
if (horizon and h > horizon[-1]) or (not horizon):
horizon.append(h)
nb_blocks += 1
return nb_blocks

Java Sudoku solver backtracking

I'm trying to build a sudoku solver. I know my code is messy and there will probably be a much simpler way to do it, but I would like finish the algorithm the way I started.
The algorithm starts doing what I want (filling the blank spaces with the first number that could fit), but when it reaches a point with no options, I don't know how to go back and erase the last number I inserted to try with another combination. But I can't just erase the last number from the matrix because it could be a number that wasn't placed by the algorithm.
If someone could help I would really appreciate it.
public class Backtracking{
public static void Sudoku(int[][] sudokuTable){
if (isAnswer(sudokuTable)){
printSudoku(sudokuTable);
}else{
for (int j = 1; j <=9; j++){
if (canfit(sudokuTable, j)){
addToSudoku(sudokuTable, j);
printSudoku(sudokuTable);
Sudoku(sudokuTable);
}
}
}
}
public static void addToSudoku(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean done = false;
while (i < 9 && !done){
while (j < 9 && !done){
if (sudokuTable[i][j] == 0){
sudokuTable[i][j] = n;
done = true;
}
j++;
}
i++;
}
}
public static void printSudoku(int[][] sudokuTable){
for (int i = 0; i < 9; i++){
for (int j = 0; j < 9; j++){
System.out.print(sudokuTable[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
public static boolean isAnswer(int[][] sudokuTable){
int sum = 0;
for (int i = 0; i < 9; i++){
for (int j = 0 ; j < 9; j++){
if (sudokuTable[i][j] > 9 || sudokuTable[i][j] < 1)
return false;
else
sum++;
}
}
if (sum != 405)
return false;
return true;
}
public static boolean canfit(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean pos = false;
boolean fit = true;
while (i < 9 && !pos){
while (j < 9 && !pos){
if (sudokuTable[i][j] == 0)
pos = true;
else
j++;
}
if (!pos)
i++;
}
for (int k = 0; k < 9; k++){
if (sudokuTable[i][k] == n && k != j)
fit = false;
}
if (fit){
for (int l = 0; l < 9; l++){
if(sudokuTable[l][j] == n && l != i)
fit = false;
}
}
if (fit){
if (i >= 0 && i < 3)
i = 0;
else if (i >=3 && i < 6)
i = 3;
else if (i >=6 && i < 9)
i = 6;
if (j >= 0 && j < 3)
j = 0;
else if (j >=3 && j < 6)
j = 3;
else if (j >=6 && j < 9)
j = 6;
for (int m = i; m < i+3; m++){
for (int o = j; o < j+3; o++){
if (sudokuTable[m][o] == n)
fit = false;
}
}
}
return fit;
}
Try to return true or false from your Sudoko method.
when isAnswer() method returns true, print table. Then return true from Sudoko() method.
Now inside your for loop, where you are calling Sudoko() method recursively, check if it returns true, or false. If it returns true, that means your choice is correct and it leads to a solution, you need not to do anything else. If it returns false, remove the number you set using addToSudoko() method. Make the table as it was before calling addToSudoko() method and continue iterating.
And if your for loop, loops for 9 times and none of the number has a suitable spot, that means if loop ends, return false.
Hope this helps
Actually you can backtracking moves by using an array, each time a move is wrong you just start to remove some moves and try a different move, however this has a problem:
the complexity of trying all possible moves is huge (how long does it takes to try all digits on a number with 81 digits? even if you cut computation time here and there , you will need all the time of the universe)
the main problem in sudoku is that you have no clue which was the wrong move if you move randomly.
Assume the following case sudoky with 2x2 cells:
+----+----++-----+-----+
| 1 | 2 || 3 | 4 |
+----+----++-----+-----+
| 4 | 3 || 1 | 2 |
+====+====++=====+=====+
| 2 | 1 || 4 | 3 |
+----+----++-----+-----+
| 3 | 4 || 2 | 1 |
+----+----++-----+-----+
If you use your algorithm in the following (unsolved) case:
+----+----++-----+-----+
| 1 | || | 4 |
+----+----++-----+-----+
| | || | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
it is possible he will run into the following sequence
+----+----++-----+-----+
| 1 | || 2 | 4 |
+----+----++-----+-----+
| | || 2 | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
Actually the added "twos" are both wrong, but when your algorithm find that those are wrong because you have 2 "twos" in the same column, you don't know which one was the wrong one (the first added, the second added, or both?)
A correct backtracking algorithm would works like this:
You start with a 81 cells arrays, and you start placing numbers (in sequence).
.
for(int i=0; i<81; i++)
array[i] = TryNumber();
.
then you check after each added number if that was correct.
.
if(SomeNumberNotCorrect())
break; // you know you can stop "tryingnumbers" so you can save on loop executions
.
But you don't know which was the wrong number
Now writing a correct algorithm that solves sudokus by attemps and do not run in million of years is pretty long and I cannot write it here but I don't think the way you choosen is the best. The best way is to apply the same strategies used by players. Just keep in mind that if you want an algorithm to resolve sudokus in a similiar way to how Chess is played by computer your algorithm would require much more time than a Chess game (infact a computer cannot analize chess moves more than 5-6 turns). But infact Sudokus can be resolved with much faster algorithms.
Instead I've already done in past a simple solver you could actually try to apply the same strategies a player would use to solve it:
In example:
For each cell, check if current Sector, Column and Line have already all numbers except 1, then you can add that number. And to check that for each cells you just need 81*81*81 moves.
When your solver do not find anymore solutions on a Sudoku, it is just because you have to develop as player a new strategy and then you need to apply it to your program, in short you will have a program that will be able to solve every sudoku (not very hard, and actually this is the reason that there are a lot of free sudoku solvers out there).

How can i recursively search for the amount of open space in a house layout?

I am taking grade 12 compsci and I am stuck on a problem regarding recursion. The context of this problem asks me to find the number of open spaces in a room given a starting row and column.
The 'X' represents the walls and the 'O' represents open space. Open space only counts if they are adjacent to each other, not diagonally.
Given this room layout, myHouse.roomSize(1,1) will return 21 and myHouse.roomSize(5,9) will return 5. if the starting row or column is a wall, it will return 0.
012345678901234567
0XXXXXXXXXXXXXXXXXX
1XOOOOOOXOOOOOOOOOX
2XXXXOOOXOOOOOOOOOX
3XOOOOOOXOOOOOOOOOX
4XOOXXXXOXXXOOOOOOX
5XOOOOXXOOOOXXXOOXX
6XXXXXXXXXXXXXXXXXX
If anyone could give me some tips on how to solve this problem with recursion
I will be extremely grateful, thanks.
Edit: Here is my attempt at solving it so far,
Edit2 (formatted now): changed maze to layout
public int roomSize (int row, int col)
{
if (layout[row][col] == 'X'|| layout [row][col]== '*')
return 0;
if (layout[row][col] == 'O')
{
layout[row][col]='*';
return 1 + roomSize(row + 1, col);
return 1 + roomSize(row, col + 1);
return 1 + roomSize(row - 1, col);
return 1 + roomSize(row, col - 1);
layout[row][col]='O';
}
}
Pseudocode to help don't want to do your work for you
int roomSize(int row, int col)
| bool [x][y] v; //Array to stored visited values x is the width of the maze y is the height
| set all bools in v to false
| return doRoomSize(row,col, v)
end
int doRoomSize(int r, int c, v)
| if( v[r][c] = true || layout [r][c]='X' )
| | return 0
| end-if
| //Now we know that its a good value
|
|This is a maze type problem so what you need to do is
int roomSize(int row, int col)
| bool [x][y] v; //Array to stored visited values x is the width of the maze y is the height
| set all bools in v to false
| return doRoomSize(row,col, v)
end
int doRoomSize(int r, int c, v)
| if( v[r][c] = true || layout [r][c]='X' )
| | return 0
| end-if
| //Now we know that its a good value
| v[r][c] = true; // we have seen this point so we addit to visted
| int n=1;
| //Check left
| n+= doRoomSize(r-1, c)
| //Check right
| n+=doRoomSize(r+1,c)
| //Check up
| n+=doRoomSize(r,c-1)
| // Check down
| n+=doRoomSize(r,c+1)
| return n;
end-method
The return statement exits the function instantly; it assumes it has found the result and that no further calculations are necessary. Your function would exit after return 1 + roomSize(row + 1, col);, assuming that it had found the result. Instead, I recommend that you use a sum or total variable which you return after the rest of the function executes.
Try this:
public int roomSize (int row, int col) {
if (layout[row][col] == 'X'|| layout [row][col]== '*')
return 0;
if (layout[row][col] == 'O') {
int total = 1;
maze[row][col]='*';
total += roomSize(row + 1, col);
total += roomSize(row, col + 1);
total += roomSize(row - 1, col);
total += roomSize(row, col - 1);
maze[row][col]='O';
}
}
EDIT: you change the value of maze to *, but when you check for * in the line ...layout[row][col] == '*'), you are not checking maze.

Categories

Resources