I've started writing a bot to play Gomoku. Briefly each player tries to score unbroken line of five tolkens. The game is played on 15*15 board.
Finding a win in one move by exhaust search is the first task.
Should I use 1D or 2D array to represent the board? 2D seems more natural, but 1D array might be faster.
What is the resource efficient way to check the winning condition?
I considered making an array.
win[i][j]=[p1,p2,p3,p4,p5], where win[i] is (the set of winning combos ) && (with one tolken in i-th position).
What would be an efficient way to do this check?
Also, how can I account for all winning combos by forking moves? The total number of winning combos will be quite large? Should I move to on the fly evaluation.
Thank you in advance,
Stepan
Should I use 1D or 2D array?
I think that you could either 1 or 2 dimension array, and with each (i, j) you could access to your cell. in 1D you must code to find correct index of the array and in 2D, simply you could access to your cells.
so in this sample code I use a 2D array.
What is the resource efficient way to check the winning condition?
you have to check the cell values with fix values (eg. booleans or numbers) frequently and the lowest assembly structure of equal statement is checking zero flag. so I think that the most efficient isEqual is for Boolean.
so in this sample code I use Boolean.
since Gomoku has 2 players, each cell could have 3 values (black, wight, empty), but we could use 2 arrays of Boolean for each player and each cell has 2 values (stone, empty) for that player.
public class Main {
final static int row = 15;
final static int column = 15;
final static int win_count = 5;
public static void main(String[] args) {
boolean[][] board1 = new boolean[row][column];
boolean[][] board2 = new boolean[row][column];
/*
* for each change by player1 in (i,j) in the board. (index start from 0
* to 14)
*/
int i = 2;
int j = 3;
Boolean win = checkWin(board1, i, j);
System.out.println("player1 win=" + win);
}
private static Boolean checkWin(boolean[][] board1, int i, int j) {
/**
* 1) check horizontal
*/
int leftBound = 0;
if (j - win_count >= 0)
leftBound = j - win_count;
else
leftBound = 0;
int rightBound = 0;
if (j + win_count < column)
rightBound = j + win_count;
else
rightBound = column - 1;
int hitCount = 0;
int jk = j;
// go left
while (jk >= leftBound && hitCount < win_count) {
if (board1[i][jk]) {
hitCount++;
jk--;
} else {
jk = j;
break;
}
}
// go right
while (jk <= rightBound && hitCount < win_count) {
if (board1[i][jk]) {
hitCount++;
jk++;
} else {
break;
}
}
if (hitCount >= win_count)
return true;
/**
* 2) check vertical
*/
/**
* 3) check principal diagonal
*/
/**
* 4) check minor diagonal
*/
// otherwise:
return false;
}
}
I write the structure of this code and you should complete other parts that is marked with comments.
I hope this sample code could help you.
Please check this article for ideas:
"Go-Moku Solved by New Search Techniques" (1993)
Briefly,
(1) A brute force 2 ply deep search is a cheap and dirty approach, but there is a better way
(2) Whenever forcing moves are involved you can run 10-20 ply deep search in a second
(3) Human professionals rely on this; your bot should utilize it as well
Hope this helps.
Related
I've got an assignment to write a NIM game with a human player and an AI player. The game is played "Misere" (last one that has to pick a stick loses). The AI is supposed to be using the Minimax algorithm, but it's making moves that make it lose faster and I can't figure out why. I've been on a dead end for days now.
The point of the Minimax algorithm is to not lose, and if it's in a losing position, delay losing as much moves as possible, right?
Consider the following:
NIMBoard board = new NIMBoard(34, 2);
34 = Binary coded positions of the sticks, 2 piles of 2 sticks
2 = the number of piles
So we start of with this scenario, the * character representing a stick:
Row 0: **
Row 1: **
In this particular board situation, the Minimax algorithm always comes up with the move "Remove 2 sticks from Row 1". This is clearly a bad move as it leaves 2 sticks in row 0, where the human player can then pick 1 stick from row 0 and win the game.
The AI player should choose to pick one stick from either pile. That leaves this for the human player:
Row 0: *
Row 1: **
So no matter which move the human player makes now, when the computer makes the next move after that, the human player will always lose. Clearly a better strategy, but why isn't the algorithm suggesting this move?
public class Minimax
{
public Move nextMove;
public int evaluateComputerMove(NIMBoard board, int depth)
{
int maxValue = -2;
int calculated;
if(board.isFinal())
{
return -1;
}
for(Move n : this.generateSuccessors(board))
{
NIMBoard newBoard = new NIMBoard(board.getPos(), board.getNumPiles());
newBoard.parseMove(n);
calculated = this.evaluateHumanMove(newBoard, depth + 1);
if(calculated > maxValue)
{
maxValue = calculated;
if(depth == 0)
{
System.out.println("Setting next move");
this.nextMove = n;
}
}
}
if(maxValue == -2)
{
return 0;
}
return maxValue;
}
public int evaluateHumanMove(NIMBoard board, int depth)
{
int minValue = 2;
int calculated;
if(board.isFinal())
{
return 1;
}
for(Move n : this.generateSuccessors(board))
{
NIMBoard newBoard = new NIMBoard(board.getPos(), board.getNumPiles());
newBoard.parseMove(n);
calculated = this.evaluateComputerMove(newBoard, depth + 1);
// minValue = Integer.min(this.evaluateComputerMove(newBoard, depth + 1), minValue);
if(calculated < minValue)
{
minValue = calculated;
}
}
if(minValue == 2)
{
return 0;
}
return minValue;
}
public ArrayList<Move> generateSuccessors(NIMBoard start)
{
ArrayList<Move> successors = new ArrayList<Move>();
for(int i = start.getNumPiles() - 1; i >= 0; i--)
{
for(long j = start.getCountForPile(i); j > 0; j--)
{
Move newMove = new Move(i, j);
successors.add(newMove);
}
}
return successors;
}
}
public class NIMBoard
{
/**
* We use 4 bits to store the number of sticks which gives us these
* maximums:
* - 16 piles
* - 15 sticks per pile
*/
private static int PILE_BIT_SIZE = 4;
private long pos;
private int numPiles;
private long pileMask;
/**
* Instantiate a new NIM board
* #param pos Number of sticks in each pile
* #param numPiles Number of piles
*/
public NIMBoard(long pos, int numPiles)
{
super();
this.pos = pos;
this.numPiles = numPiles;
this.pileMask = (long) Math.pow(2, NIMBoard.PILE_BIT_SIZE) - 1;
}
/**
* Is this an endgame board?
* #return true if there's only one stick left
*/
public boolean isFinal()
{
return this.onePileHasOnlyOneStick();
}
/**
* Figure out if the board has a pile with only one stick in it
* #return true if yes
*/
public boolean onePileHasOnlyOneStick()
{
int count = 0;
for(int i = 0; i < this.numPiles; i++)
{
count += this.getCountForPile(i);
}
if(count > 1)
{
return false;
}
return true;
}
public int getNumPiles()
{
return this.numPiles;
}
public long getPos()
{
return this.pos;
}
public long getCountInPile(int pile)
{
return this.pos & (this.pileMask << (pile * NIMBoard.PILE_BIT_SIZE));
}
public long getCountForPile(int pile)
{
return this.getCountInPile(pile) >> (pile * NIMBoard.PILE_BIT_SIZE);
}
public void parseMove(Move move)
{
this.pos = this.pos - (move.getCount() << (move.getPile() * NIMBoard.PILE_BIT_SIZE));
}
#Override
public String toString()
{
String tmp = "";
for(int i = 0; i < this.numPiles; i++)
{
tmp += "Row " + i + "\t";
for(int j = 0; j < this.getCountForPile(i); j++)
{
tmp += "*";
}
tmp += System.lineSeparator();
}
return tmp.trim();
}
}
The move that you suppose is a better move for the AI is not actually a better move. In that board situation, the human player would take two sticks from Row 1, and the computer is still stuck taking the last stick. That doesn't guarantee your program is working correctly, but I think you should try some different test cases. For example, see what the AI does if you give it the situation where you supposed the human player would lose.
You are not supposed to have a different function for the human player. You should assume both players use the best strategy and since you're implementing it it should be the same code for both players.
The idea of the algorithm is not to assign a state id to the current state equal to the minimum state id that doesn't overlap any state id of the states that you could end up. If you can make a move and reach state with ids 0, 1, and 3 then the current state should have state id 2.
Any losing state should have id 0.
If your current state has state id 0 you lose no mater what move you make. Otherwise you can find a move that moves the board into a state with id 0 which means the other player will lose.
I've created a Sudoku solver that will solve a Sudoku as a human might- by checking possibilities + definite values in squares corresponding to the square being checked.
(Source: http://pastebin.com/KVrXUDBF)
However, I would like to create a random Sudoku generator (from a blank grid), and so have decided to use a backtracking algorithm. I understand the concept of backtracking, but am confused about one thing:
How do I know which previous node to return to (and change) once I know a certain solution is not allowed?
Should I simply return to the previous node and cycle through all possibilities? (And then if this yields no correct answers, return to the value before, etc.). This seems like a viable method, but also quite inefficient. Is this the correct way of implementing a backtracking method or is there a better way to go about it?
Thanks in advance.
More can be found about backtracking here: http://en.wikipedia.org/wiki/Backtracking
Sudoku Puzzle can be reduced to graph coloring problem which can be solved using simple backtracking like assigning colors to node (1-9) till the there is no violation that all directly connected nodes have no same color.
Constructing Graph from Sudoku : -
There is an direct edge between two grid points if they are in same
row or column or square.
Backtracking :-
Assign one color (1-9) to node
Check if there is no other directly connected node with same color
If valid color move to next node.
else change the color and recheck.
If all color exhausted backtrack to previous node.
Do recursion till all nodes are color.
Once You are done with it you can start removing numbers from the grid at random till you think the problem is unsolvable if any more numbers are removed.
A simple way to generate random Sudoku is that
1) generate a random completing Sudoku, that is, generate random Sudoku no square is blank.
2) Remove numbers from squares of 1).
3) Solve Sudoku of 2). If there are many solutions, then add a number removed at 2).
If there are still many solutions, then repeat 3).
1) sample source code:
public int[][] generateRandomCompleteSudoku() {
int[][] sudoku = new int[10];
for(int i = 1; i <= 9; i++) {
sudoku[i] = new int[10];
Arrays.fill(sudoku[i], 0);
}
generateRandomCompleteSudoku(sudoku, 1, 1);
return sudoku;
}
private boolean generateRandomCompleteSudoku(int[][] sudoku, int x, int y) {
if(x > 9) {
x = 1;
y++;
}
//sudoku of the argument is completing sudoku.
//so return true
if(y > 9) {
return true;
}
// enumerate the possible numbers of the pos(x,y).
List<Integer> possibleNumbers = new ArrayList<Integer>();
for(int i = 1; i <= 9; i++) {
boolean possible = true;
//check i is a possible number.
//check there isn't i in the raw of y .
for(int j = 1; j <= x - 1; j++) {
if(sudoku[j][y] == i) {
possible = false;
break;
}
}
//check there isn't i in the column of x(omitted).
//check there isn't i in the group of x,y(omitted).
if(possible) {
possibleNumbers.add(i);
}
}
//sudoku is wrong so return false.(There is no solution of sudoku)
if(possibleNumbers.size() <= 0) {
return false;
}
Collections.shuffle(possibleNumbers);// This gives sudoku randomness.
for(Integer possibleNumber : possibleNumbers) {
sudoku[x][y] = possibleNumber;
// a sudoku is generated, so return true
if(generateRandomCompleteSudoku(sudoku, x + 1, y)) {
return true;
}
}
// No sudoku is generated, so return false
return false;
}
For a backtracking solution, the first step is to define the state. So for this problem, I think the most straightforward way is (x,y, blank , num) with x , y is the position of the current state, blank is the number of blank position left, and num is the value you want to fill in that position (from 0 to 9 and 0 means blank).
And the return type should be boolean, which determine whether the move is valid or not (which means is there any valid solution for this move).
So, the state transition is column by column, row by row: x, y to x , (y + 1) or x , y to (x + 1), 0.
Similarly, the blank will be from a -> a - 1-> ... 0.
We have a draft solution here:
public boolean move(int x, int y, int blank, int num, int[][]sudoku){
sudoku[x][y] = num;
//checking condition and return if x,y is the last position, code omitted
if(y == sudoku[x].length){
x++;
y = 0;
}else{
y++;
}
for(int i = 1; i < 10; i++){
if(move(x,y,blank,i,sudoku){//Backtrack here
return true;
}
}
if(blank > 0){
if(move(x,y,blank - 1, 0, sudoku){//Backtrack here
return true;
}
}
return false;
}
So when ever there is a false return from the current state, it will backtrack to the last state , and the last state will continue to check for the next num until it find a correct solution (or return false).
I am using a method (as shown below) that allows me to input the amount of players along with a name for each player. Is there a way for me to use this array to decide who is the active player? (turn based guessing game). If you could just point me in the right direction.
public class Program {
String[] playerList;
int playersAmount = 0;
public void inputPlayers() {
playersAmount = Input.readInt();
playerList= new String[playersAmount];
for (int g = 0; g < playersAmount; g++) {
String namePlayer = "player " + (g+1);
playerList [g] = namePlayer;
}
}
}
You should look over the question I had about changing the player number. I think this exactly what you are looking for (or something similar): Java: Changing Player Number
Essentially I used a boolean array to keep track of who is still playing where the array index corresponds to the player number a[0] = Player 0, a[1] = Player 1, etc. If a player gets eliminated mark the corresponding index with false: a[i] = false; You can then use the following method (taken from my question) to switch the player number to the next player still playing:
public static int switchPlayer(int currentPlayer, boolean[] playerList) {
// if the current player + 1 = length (size) of array,
// start back at the beginning and find the first player still playing
if(currentPlayer + 1 == playerList.length) {
for(int i = 0; i < playerList.length; i++) {
if(playerList[i] == true) { // if player is still in the game
currentPlayer = i; // currentPlayer = current index of array
break;
}
}
}
// otherwise the current player number + 1 is not at the end of the array
// i.e. it is less than the length (size) of the array, so find the next player
// still playing
else {
for(int i = (currentPlayer+1); i < playerList.length; i++) {
if(playerList[i] == true) {
currentPlayer = i;
break;
}
}
}
return currentPlayer;
}
Let me know if you have any questions about my code, etc.
You have two different options in my opinion.
create a Player object with instance variables as his name and a boolean that states whether or not he is active.
You can create a boolean array that is sync with the player array that states wether or not the player is active.
ex for 2
boolean[] activeStatus= new boolean[1];
String[] players = new String[1];
activeStatus[0]=true;
players[0]="Joe Smith";
Well, to represent the current player you can use a int
int curplayer = 0;
Every time their round is done you can add one to get the index of the next player.
curplayer++;
As for it returning to the first player after the last player, I suggest you look into the % (modulo) operator.
Keep track of the turn number using an instance variable:
private int turn;
Increment it every turn:
turn++;
The index of the player whose turn it is can be calculated by using the remainder of dividing the turn by the number of players:
int playerIndex = turn % playersAmount;
I leave it to you to work these parts into your code.
My java is a bit rusty, but something like the following should work.
i = 0
while (playing == True)
{
player = playerList[i]
i = (i + 1) % playerList.length
[Do something]
}
I'm making a game for a class and one element of the game is displaying a number of cabbages, which are stored in an ArrayList. This ArrayList must be a fixed number of 20, 10 of Good Cabbage and 10 of Bad Cabbage.
As the cabbages are created, I want to make sure they don't overlap when they are displayed. Where I'm running into trouble with this is that when I find a cabbage that overlaps, I'm not sure how to go back and create a new cabbage in its place. So far when the code finds an overlap, it just stops the loop. I guess I'm having trouble properly breaking out of a loop and restarting at the index that goes unfilled.
Here's what I have so far for this. Any suggestions would be much appreciated.
// Initialize the elements of the ArrayList = cabbages
// (they should not overlap and be in the garden) ....
int minX = 170 ;
int maxX = 480;
int minY = 15;
int maxY = 480;
boolean r = false;
Cabbage cabbage;
for (int i = 0; i < N_GOOD_CABBAGES + N_BAD_CABBAGES; i++){
if (i % 2 == 0){
cabbage = new GoodCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
else {
cabbage = new BadCabbage((int)(Math.random()* (maxX-minX + 1))+ minX,
(int)(Math.random()*(maxY-minY + 1))+ minY,window);
}
if (i >= cabbages.size()){
// compares the distance between two cabbages
for (int j = 0; j < cabbages.size(); j++){
Point c1 = cabbage.getLocation();
Cabbage y = (Cabbage) cabbages.get(j);
Point c2 = y.getLocation();
int distance = (int) Math.sqrt((Math.pow((c1.x - c2.x), 2) + Math.pow((c1.y - c2.y),2)));
if (distance <= (CABBAGE_RADIUS*2) && !(i == j)){
r = true;
}
}
if (r){
break;
}
cabbage.draw();
cabbages.add(i, cabbage);
}
}
The easiest way to do this is probably to add another loop.
A do...while loop is suited to cases where you always need at least one iteration. Something like:
boolean overlapped;
do {
// create your new cabbage here
overlapped = /* check whether it overlaps another cabbage here */;
} while (overlapped);
cabbage.draw();
cabbages.add(i, cabbage);
It looks like you are making cabbage objects and then throwing them away, which is a (trivial) waste.
Why not pick the random X and Y, check if there is room at that spot, then make the cabbage when you have a good spot? You'll just churn through numbers, rather than making and discarding entire Objects. Plus you won't have to repeat the random location code for good and bad cabbages.
int x, y
do {
// pick x and y
} while (cabbageOverlaps(x,y,list)
// create a cabbage at that x,y, and add it to list
boolean cabbageOverlaps(int x, int y, ArrayList existingCabbages)
I have to create a program that finds all the possible ways of filling a square of size x by y. You place a block which takes up 2 spaces to completely fill.
The problem is I don't know how to code it to the point where you can remember the placements of each square. I can get it to where it fills the board completely once and maybe twice, but nothing past that. I also know that I'm supposed to use recursion to figure this out . Here is the code I started on so far. There is also a main method and I have the initial even/odd check working fine. This is the part I have no idea on.
public void recurDomino(int row, int column) {
if (Board[2][x - 1] != false) {
} else if(Board[1][x-1]!=false)
{
}
else {
for (int n=0; n < x - 1; n++) {
Board[row][column] = true;
Board[row][column+1] = true;
column++;
counter++;
}
recurDomino(1, 0);
recurDomino(2, 0);
}
}
Thank you for any help you guys can give me.
******************* EDIT ****************************************
I am a little confused still. I came up with this algorithm but I always get 2 for any value greater or equal to 2.
public boolean tryHorizontal(int row , int col){
if( row < 0 || row >= array[0].length-1)
return false;
else
return true;
}
public boolean tryVertical(int row, int col){
if( col < 0 || col >= 2 )
return false;
else
return true;
}
public boolean tryRowCol(int row, int col){
if(this.tryHorizontal(row, col) && this.tryVertical(row, col)){
return true;
}
else
return false;
}
public int findWays(int row, int col){
int n = 0;
if( !this.tryRowCol(row, col))
return 0;
else
n =+ 1 + this.findWays(row+1, col+1);
return n;
}
This recursive solution actually generates all the possible tiling of a general MxN board. It's more general than what your program requires, and therefore not optimized to just count the number of tiling of a 3xN board.
If you just want to count how many there are, you can use dynamic programming techniques and do this much faster. Also, having the number of rows fixed at 3 actually makes the problem considerably easier. Nonetheless, this general generative solution should be instructive.
public class Domino {
final int N;
final int M;
final char[][] board;
int count;
static final char EMPTY = 0;
Domino(int M, int N) {
this.M = M;
this.N = N;
board = new char[M][N]; // all EMPTY
this.count = 0;
generate(0, 0);
System.out.println(count);
}
void printBoard() {
String result = "";
for (char[] row : board) {
result += new String(row) + "\n";
}
System.out.println(result);
}
void generate(int r, int c) {
//... see next code block
}
public static void main(String[] args) {
new Domino(6, 6);
}
}
So here's the meat and potatoes:
void generate(int r, int c) {
// find next empty spot in column-major order
while (c < N && board[r][c] != EMPTY) {
if (++r == M) {
r = 0;
c++;
}
}
if (c == N) { // we're done!
count++;
printBoard();
return;
}
if (c < N - 1) {
board[r][c] = '<';
board[r][c+1] = '>';
generate(r, c);
board[r][c] = EMPTY;
board[r][c+1] = EMPTY;
}
if (r < M - 1 && board[r+1][c] == EMPTY) {
board[r][c] = 'A';
board[r+1][c] = 'V';
generate(r, c);
board[r][c] = EMPTY;
board[r+1][c] = EMPTY;
}
}
This excerpt from the last few lines of the output gives an example of a generated board, and the final count.
//... omitted
AA<><>
VVAA<>
AAVV<>
VVAA<>
<>VVAA
<><>VV
//... omitted
6728
Note that 6728 checks out with OEIS A004003.
A few things that you need to learn from this solutions are:
Clean-up after yourself! This is a very common pattern in recursive solution that modifies a mutable shared data. Feel free to do your thing, but then leave things as you found them, so others can do their thing.
Figure out a systematic way to explore the search space. In this case, dominoes are placed in column-major order, with its top-left corner as the reference point.
So hopefully you can learn something from this and adapt the techniques for your homework. Good luck!
Tip: if you comment out the printBoard line, you can generate all ~13 million boards for 8x8 in reasonable time. It'll definitely be much faster to just compute the number without having to generate and count them one by one, though.
Update!
Here's a recursive generator for 3xN boards. It doesn't use a shared mutable array, it just uses immutable strings instead. It makes the logic simpler (no clean up since you didn't make a mess!) and the code more readable (where and how the pieces are placed is visible!).
Since we're fixed at 3 rows, the logic is more explicit if we just have 3 mutually recursive functions.
public class Domino3xN {
static int count = 0;
public static void main(String[] args) {
addRow1(8, "", "", "");
System.out.println(count);
}
static void addRow1(int N, String row1, String row2, String row3) {
if (row1.length() == N && row2.length() == N && row3.length() == N) {
count++; // found one!
System.out.format("%s%n%s%n%s%n%n", row1, row2, row3);
return;
}
if (row1.length() > row2.length()) { // not my turn!
addRow2(N, row1, row2, row3);
return;
}
if (row1.length() < N - 1)
addRow2(N, row1 + "<>",
row2,
row3);
if (row2.length() == row1.length())
addRow3(N, row1 + "A",
row2 + "V",
row3);
}
static void addRow2(int N, String row1, String row2, String row3) {
if (row2.length() > row3.length()) { // not my turn!
addRow3(N, row1, row2, row3);
return;
}
if (row2.length() < N - 1)
addRow3(N, row1,
row2 + "<>",
row3);
if (row3.length() == row2.length())
addRow1(N, row1,
row2 + "A",
row3 + "V");
}
static void addRow3(int N, String row1, String row2, String row3) {
if (row3.length() == row2.length()) { // not my turn!
addRow1(N, row1, row2, row3);
return;
}
if (row3.length() < N - 1)
addRow1(N, row1,
row2,
row3 + "<>");
}
}
You don't often see 3 mutually recursive functions like this, so this should be educational.
One way of doing it is with the CSP (Constraint Satisfaction Problem) approach:
Consider every cell in the grid to be a variable, with 4 possible values (indicating the part of the domino it takes). Some assignments are obviously illegal. Legal assignments assign values to a "neighboring variable" as well. Your goal is to assign all the 3xN variables with legal values.
The recursion here can help you cover the state space easily. On each invocation, you try to assign a value to the next unasigned cell, by trying all the 4 options. After each successfull assignment, you can call the same method recursively, and then undo your last assignment (this way you don't have to clone anything - one copy of the grid data is enough).
--EDIT--
If you want to do it efficiently so that it works for large values on N in reasonable time, you will also have to think about optimizations, in order to discard some assignment attempts.
Here are some hints:
With a fixed-size board you can precompute the exact number of steps that each solution takes, so the termination criterion is trivial: you just check the nesting level.
Starting from one corner is a good idea, because it means that you can always find a field that can only be covered in two different ways (vertically or horizontally).
That means that you have a branching factor of only 2, and a recursion depth of 3*N/2, which is probably small enough that you can just clone the sstate of the board for each call (ordinarily you would construct new states incrementally from existing states to save space, but that is a bit harder to program).
In many states here will be more than one field that allows only two possibilities; with a clever strategy for choosing the next field, you can ensure that you will never find the same solution via two different paths, so you don't even have to check the solutions for duplicates.
The state of the board must record which fields are free and which fields are occupied, but also which fields are occupied by the same domino, so an array of int could do the trick.