1

I am programming an AI for a chess-like game, based on two types of pieces on a 8 x 8 grid.

I want to build a kind of minmax tree, which represents each possible move in a game, played by white players in first, and by black players in second.

I have this generate() method which is call recursively. I need to be able to display about 8 levels of possible moves. Without optimization, this three has 8^8 leafs.

I implemented a simple system which determinate if a grid has actually ever been calculated and if its the case, system just points a child to the ever-calculated child reference.

I don't know if my explanations are clear, I will join a part of code that you should be able to understand.

The problem is that actually, I am able to generate about 3 or 4 levels of all possibilities. I am far of 8.

I would like to be able to calculate it in less than 5 seconds..

So guys, do you see a solution for optimize my algorithm ?

This is the generate function: leftDiagonalMove(), rightDiagonalMove() and frontMove() return false if a move is illegal or move the piece in the grid and return true, if the move is legal.

clone() creates a new instance with the same properties of it's "parent" and backMove() just step back to last Move.

public void generate(Node root, boolean white, int index) {

    Grid grid = root.getGrid();

    Stack<Piece> whitePieces = grid.getPiecesByColor(WHITE);
    Stack<Piece> blackPieces = grid.getPiecesByColor(BLACK);
    Node node;

    String serial = "";
    // white loop
    for (int i = 0; i < whitePieces.size() && white; i++) {
        Piece wPiece = whitePieces.get(i);

        if (grid.leftDiagonalMove(wPiece)) {
            serial = grid.getSerial();
            if(!allGrids.containsKey(serial)){
                node = new Node(grid.clone());
                node.setMove(grid.getLastMove());
                root.addChild(node); // add modified grid
                allGrids.put(serial, node);
                //actualGrid.display();
                if (index < 5 && grid.getPosition(wPiece).x > 0)
                    generate(node, !white, index + 1);
                actualGrid.backMove(); // back step to initial grid
            }
            else{
                root.addChild(allGrids.get(serial));
            }
        }

        if (grid.frontMove(wPiece)) {
            // same code as leftMove
        }

        if (grid.rightDiagonalMove(wPiece)) {
            // same code as leftMove
        }

    }

    // black loop
    for (int i = 0; i < blackPieces.size() && !white; i++) {
        Piece bPiece = blackPieces.get(i);

        if (grid.leftDiagonalMove(bPiece)) {
            // same code as white loop and replacing wPiece by bPiece
        }

        if (grid.frontMove(bPiece)) {
            // same code as white loop and replacing wPiece by bPiece
        }

        if (grid.rightDiagonalMove(bPiece)) {
            // same code as white loop and replacing wPiece by bPiece
        }

    }

}
trincot
  • 317,000
  • 35
  • 244
  • 286
Pier-Alexandre Bouchard
  • 5,135
  • 5
  • 37
  • 72
  • 1
    When you profile your application, what does it spend most of its time doing? – Peter Lawrey Mar 14 '12 at 19:59
  • Why don't you use Neural Network for this? – formatc Mar 14 '12 at 20:00
  • 1
    One thing I notice is that you recreate a new object every single time you're pulling it from the `ArrayList`. Moving your declarations of Piece outside of the loop would help reduce memory footprint and help improve runtime somewhat. Otherwise, you would be better served using a Java code profiler to see how often your code is doing what calls where and why. – Makoto Mar 14 '12 at 20:02
  • @PeterLawrey I don't know of to profile my memory. I am using Eclipse, but I do not have any tool for this.. – Pier-Alexandre Bouchard Mar 14 '12 at 20:10
  • A Neural Network, could help in memory ? – Pier-Alexandre Bouchard Mar 14 '12 at 20:10
  • 3
    @Makoto No. He doesn't 'recreate a new object' every time around the loop. He *declares* a new *variable* every time around the loop. The impact of that at runtime is zero, because the stack slot was already allocated at entry to the method, by the definition of the Java bytecode. – user207421 Mar 14 '12 at 22:52
  • In my experience, unless you measure the performance characteristics of your program (You can start with VisualVM, and later try a commercial profiler like YourKit), you will be just guessing. You can find that what you think are performance improvements, just make your code more complex and can make it slower. Conversely, minor changes which you wouldn't think of can make a big difference. The best place to start is with a profiler and a realistic use case. – Peter Lawrey Mar 15 '12 at 08:29
  • @PeterLawrey I will try VisualVM, I never used this kind of tool. – Pier-Alexandre Bouchard Mar 15 '12 at 20:54
  • You should also try using a commercial profiler like YourKit (You can get a evaluation license for free so you don't have to pay for it to try it) – Peter Lawrey Mar 16 '12 at 08:54

2 Answers2

3

You need to use something called AlphaBeta pruning on your generated MinMax trees of moves. More on this here: http://en.wikipedia.org/wiki/Alpha-beta_pruning
http://www.progtools.org/games/tutorials/ai_contest/minmax_contest.pdf

Basically you do one level of branches and then using pruning you eliminate bad branches early. Then from the non eliminated branches you calculate (for each) another level. You prune again until you reach a desired depth.

Here are a few more links for you to read up on minmax:
1. http://en.wikipedia.org/wiki/Minimax
2. MinMax trees - when Min can win in two steps

This one is on optimizing pruning for chess games:
1. http://en.wikipedia.org/wiki/Alpha-beta_pruning#Heuristic_improvements
2. http://en.wikipedia.org/wiki/Refutation_table#Related_techniques

Community
  • 1
  • 1
Adrian
  • 5,603
  • 8
  • 53
  • 85
  • But by eliminating bad branches, I will not calculate every possibilities ? – Pier-Alexandre Bouchard Mar 14 '12 at 20:12
  • @Pier-alexandreBouchard if you know that you will lose going out on a losing branch why do you still want to calculate losing moves? This algo just cuts bad branches early (I assumed you were interested in good moves not in finding out all moves). – Adrian Mar 14 '12 at 20:16
0

I don't understand why you are using Stacks when you are doing random access to the elements. A a low level you would get an improvement by using a Piece[] array instead.

user207421
  • 305,947
  • 44
  • 307
  • 483