Package com.barrybecker4.game.twoplayer.blockade.board.analysis

Source Code of com.barrybecker4.game.twoplayer.blockade.board.analysis.ShortestPathFinder

// Copyright by Barry G. Becker, 2012. Licensed under MIT License: http://www.opensource.org/licenses/MIT
package com.barrybecker4.game.twoplayer.blockade.board.analysis;

import com.barrybecker4.game.common.GameContext;
import com.barrybecker4.game.twoplayer.blockade.board.BlockadeBoard;
import com.barrybecker4.game.twoplayer.blockade.board.BlockadeBoardPosition;
import com.barrybecker4.game.twoplayer.blockade.board.Homes;
import com.barrybecker4.game.twoplayer.blockade.board.move.BlockadeMove;
import com.barrybecker4.game.twoplayer.blockade.board.path.Path;
import com.barrybecker4.game.twoplayer.blockade.board.path.PathList;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
* Finds the shortest path from a given position to a home base.
*
* @author Barry Becker
*/
class ShortestPathFinder {

    private BlockadeBoard board;
    private PossibleMoveAnalyzer moveAnalyzer;

    /**
     * Constructor.
     */
    public ShortestPathFinder(BlockadeBoard board) {
        this.board = board;
        moveAnalyzer = new PossibleMoveAnalyzer(board);
    }

    /**
     * Find the shortest paths from the specified position to opponent homes.
     * We use DefaultMutableTreeNodes to represent nodes in the path.
     * If the number of paths returned by this method is less than NUM_HOMES,
     * then there has been an illegal wall placement, since according to the rules
     * of the game there must always be paths from all pieces to all opponent homes.
     * If a pawn has reached an opponent home then the path magnitude is 0 and that player won.
     *
     * @param position position to check shortest paths for.
     * @return the NUM_HOMES shortest paths from toPosition.
     */
    public PathList findShortestPaths(BlockadeBoardPosition position)  {

        boolean opponentIsPlayer1 = !position.getPiece().isOwnedByPlayer1();
        // set of home bases
        // use a LinkedHashMap so the iteration order is predictable.
        Set<MutableTreeNode> homeSet = new LinkedHashSet<MutableTreeNode>();
        // mark position visited so we don't circle back to it.
        position.setVisited(true);

        List<DefaultMutableTreeNode> queue = new LinkedList<DefaultMutableTreeNode>();
        // the user object at the root is null, because there is no move there.
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(null);
        // if we are sitting on a home, then need to add it to the homeBase set.
        if (position.isHomeBase(opponentIsPlayer1)) {
           homeSet.add(root);
        }
        else {
            queue.addAll(findPathChildren(position, root, opponentIsPlayer1));

            // do a breadth first search until you have spanned/visited all opponent homes.
            while (homeSet.size() < Homes.NUM_HOMES && !queue.isEmpty()) {
                // pop the next move from the head of the queue.
                DefaultMutableTreeNode node = queue.remove(0);
                BlockadeMove nodeMove = (BlockadeMove)node.getUserObject();
                BlockadeBoardPosition toPosition =
                        board.getPosition(nodeMove.getToRow(), nodeMove.getToCol());
                if (!toPosition.isVisited()) {
                    toPosition.setVisited(true);
                    MutableTreeNode parentNode = (MutableTreeNode)node.getParent();
                    node.setParent(null);
                    parentNode.insert(node, parentNode.getChildCount());
                    if (toPosition.isHomeBase(opponentIsPlayer1)) {
                        homeSet.add(node);
                    }
                    List<DefaultMutableTreeNode> children = findPathChildren(toPosition, node, opponentIsPlayer1);
                    queue.addAll(children);
                }
            }
        }
        // extract the paths by working backwards to the root from the homes.
        PathList paths = extractPaths(homeSet);

        unvisitAll();
        return paths;
    }

    /**
     * Find moves going to unvisited positions that can be reached without going through walls.
     * @param pos the place we are moving from.
     * @param parent the parent node for the child moves
     * @param oppPlayer1 the opposing player (opposite of pies at pos).
     * @return a list of TreeNodes containing all the moves that lead to unvisited positions.
     */
    private List<DefaultMutableTreeNode> findPathChildren(
            BlockadeBoardPosition pos, MutableTreeNode parent, boolean oppPlayer1) {
        List<BlockadeMove> moves = moveAnalyzer.getPossibleMoveList(pos, oppPlayer1);
        List<DefaultMutableTreeNode> children = new ArrayList<DefaultMutableTreeNode>();

        for (BlockadeMove move : moves) {
            DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(move);
            childNode.setParent(parent);
            children.add(childNode);
        }
        return children;
    }

    /**
     * return everything to an unvisited state.
     */
    private void unvisitAll() {
        for ( int i = 1; i <= board.getNumRows(); i++ ) {
            for ( int j = 1; j <= board.getNumCols(); j++ ) {
                board.getPosition(i, j).setVisited(false);
            }
        }
    }

    /**
     * There will be a path to each home base from each pawn.
     * Extract the paths by working backwards to the root from the homes.
     * @param homeSet set of home base positions.
     * @return extracted paths
     */
    private PathList extractPaths(Set<MutableTreeNode> homeSet) {
        PathList paths = new PathList();

        for (MutableTreeNode home : homeSet) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)home;
            Path path = new Path(node);
            // if the path is not > 0 then then pawn is on the homeBase and the game has been won.
            if (path.getLength() == 0) {
                GameContext.log(2, "found 0 magnitude path =" + path +" for home "  + node);
            }
            paths.add(path);
        }
        return paths;
    }
}
TOP

Related Classes of com.barrybecker4.game.twoplayer.blockade.board.analysis.ShortestPathFinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.