/** * Represents a position in Path Myopic Col. * * @author Kyle Burke <paithanq@gmail.com> * */ import java.lang.*; import java.io.*; import java.util.*; public class PathMyopicCol extends CombinatorialGame { /* constants */ /** * Represents uncolored. */ public static int UNCOLORED = 2; //represents the color names private String[] colorNames = new String[] {"Blue", "Red ", " "}; /* instance variables */ //Array of references to the head of each path. private PureLinkedList<Integer> path; /** * Class constructor for a board with randomly-colored spaces. * * @param length The length of the path to create. * @param density The probability that each vertex will be colored. * @throws IllegalArgumentException If any of the lengths is non-positive. */ public PathMyopicCol(int length, double density) throws IllegalArgumentException { if (length <1) { throw new IllegalArgumentException("Tried to create a path with non-positive length of " + length + "!"); } //first, copy the lengths Random random = new Random(); int color=UNCOLORED; if (random.nextDouble() <= density) { if (random.nextDouble() < .5) { color = CombinatorialGame.LEFT; } else { color = CombinatorialGame.RIGHT; } } this.path = new PureLinkedList<Integer>(color); for (int i = 1; i < length; i++) { color = UNCOLORED; if (random.nextDouble() <= density) { if (random.nextDouble() < .5) { color = CombinatorialGame.LEFT; } else { color = CombinatorialGame.RIGHT; } } this.path.add(new Integer(color)); } } /** * Constructor for a board with spaces that may be colored. * * @param path LinkedList that represents the colors of this board. */ public PathMyopicCol(PureLinkedList<Integer> path) { //this.paths = new ArrayList<PureLinkedList<Integer>>(); this.path = this.copyPath(path); ArrayList<Integer> legalColors = new ArrayList<Integer>(); legalColors.add(UNCOLORED); legalColors.add(CombinatorialGame.LEFT); legalColors.add(CombinatorialGame.RIGHT); for (int i = 0; i < this.path.length(); i++) { if (!legalColors.contains(this.path.get(i))) { throw new IllegalArgumentException("Tried to create a path with an illegal color: " + this.path.get(i)); } } } //copies a path private static PureLinkedList<Integer> copyPath(PureLinkedList<Integer> path) { PureLinkedList<Integer> pathCopy = new PureLinkedList<Integer>(path.getFirst()); PureLinkedList<Integer> pathCopyHead = pathCopy; //alias the first element of pathCopy while (!path.isLast()) { //add the next thing in path to pathCopy path = path.getTail(); pathCopy.setTail(new PureLinkedList<Integer>(path.getFirst())); pathCopy = pathCopy.getTail(); } return pathCopyHead; } /* public methods */ /** * Returns a String version of this. * * @return A String description of this. */ public String toString() { StringBuffer buffer = new StringBuffer(); PureLinkedList<Integer> path = this.path; while (path != null) { Integer color = path.getFirst(); buffer.append("[" + this.getColorName(color) + "]"); if (!path.isLast()) { buffer.append("-->"); } path = path.getTail(); } return buffer.toString(); } /** * Clones this. * * @return A deep clone of this. */ public CombinatorialGame clone() { return new PathMyopicCol(this.path); } /** * Determines whether two positions are identical. * * @param other The other position to compare to this. */ public boolean equals(CombinatorialGame other) { PathMyopicCol otherCol; try { otherCol = (PathMyopicCol) other; return this.path.equals(otherCol.path); } catch (ClassCastException cce) { //other isn't a PathMyopicCol instance return false; } } /** * Gets the paths. * * @return A copy of the paths of this. */ public PureLinkedList<Integer> getPath() { return copyPath(this.path); } @Override public Collection<CombinatorialGame> getOptions(int player) { Collection<CombinatorialGame> options = new ArrayList<CombinatorialGame>(); for (int nodeIndex = 0; nodeIndex < this.path.length(); nodeIndex ++) { int nodeColor = this.path.get(nodeIndex).intValue(); if (nodeColor == UNCOLORED) { if ((nodeIndex == this.path.length() - 1) || (this.path.get(nodeIndex + 1).intValue() != player)) { //coloring the current node is a legal move. Let's generate it! //first, copy the position PathMyopicCol option = (PathMyopicCol) this.clone(); //then, set the new color //System.out.println("nodeIndex: " + nodeIndex); //System.out.println("nodeColor: " + nodeColor); //System.out.println("this.path: " + this.path); option.path.set(nodeIndex, new Integer(player)); options.add(option); } } } return options; } /* public classes */ public static class PositionBuilder implements PositionFactory<PathMyopicCol> { //minimum length of a path private int minPathLength; //maximum length of a path private int maxPathLength; //likelihood of coloring private double colorDensity; /** * Class constructor. * * @param minPathLength The shortest possible length of the path. * @param maxPathLength The longest possible length of the path. * @param colorDensity The probability that a given vertex is colored. */ public PositionBuilder(int minPathLength, int maxPathLength, double colorDensity) { this.minPathLength = minPathLength; this.maxPathLength = maxPathLength; this.colorDensity = colorDensity; } @Override public PathMyopicCol getPosition() { Random random = new Random(); int length = minPathLength + random.nextInt(maxPathLength - minPathLength); return new PathMyopicCol(length, colorDensity); } } //end of PositionFactory /* private methods */ //gets the name of the color private String getColorName(int colorCode) { return this.colorNames[colorCode]; } //gets the name of the color private String getColorName(Integer colorCode) { return this.getColorName(colorCode.intValue()); } /* main method for testing */ /** * Tests the functionality of this class. * * @param args Strings used in command line tests of this. */ public static void main(String[] args) { PositionFactory<PathMyopicCol> factory = new PathMyopicCol.PositionBuilder(6, 10, .2); System.out.println(factory.getPosition()); //this is all for the old version, which had multiple lists! /* //test the empty-game constructor ArrayList<Integer> lengths = new ArrayList<Integer>(); lengths.add(3); lengths.add(5); PathMyopicCol empty = new PathMyopicCol(lengths); System.out.println("An empty 3-5 position:"); System.out.println(empty); //test the partially-played constructor with one path ArrayList<PureLinkedList<Integer>> paths = new ArrayList<PureLinkedList<Integer>>(); PureLinkedList<Integer> path = new PureLinkedList<Integer>(CombinatorialGame.RIGHT); path.add(CombinatorialGame.LEFT); path.add(UNCOLORED); path.add(CombinatorialGame.LEFT); path.add(UNCOLORED); path.add(CombinatorialGame.RIGHT); paths.add(path); PathMyopicCol onePath = new PathMyopicCol(paths); System.out.println("A position with one path: \n" + onePath); //now add another path path = new PureLinkedList<Integer>(UNCOLORED); path.add(CombinatorialGame.LEFT); path.add(CombinatorialGame.LEFT); path.add(CombinatorialGame.RIGHT); paths.add(path); PureLinkedList<Integer> blankPath = new PureLinkedList<Integer>(UNCOLORED); blankPath.add(UNCOLORED); paths.add(blankPath); paths.add(path); System.out.println("Should still just have one path: \n" + onePath); //test the constructor on a game with many paths PathMyopicCol multiPaths = new PathMyopicCol(paths); System.out.println("Should have more paths: \n" + multiPaths); //test number of paths System.out.println("Should say 1: " + onePath.numberOfPaths()); System.out.println("Should say 4: " + multiPaths.numberOfPaths()); //test clone PathMyopicCol threePathsClone = (PathMyopicCol) multiPaths.clone(); System.out.println("Copy of multiPaths: \n" + threePathsClone); //test equals //easy true tests System.out.println("Should say true: " + multiPaths.equals(threePathsClone)); System.out.println("Should say true: " + threePathsClone.equals(multiPaths)); //false tests System.out.println("Should say false: " + onePath.equals(multiPaths)); System.out.println("Should say false: " + multiPaths.equals(new PathMyopicCol(new ArrayList<PureLinkedList<Integer>>()))); //more complex true tests paths = new ArrayList<PureLinkedList<Integer>>(); paths.add(blankPath); paths.add(path); paths.add(path); path = new PureLinkedList<Integer>(CombinatorialGame.RIGHT); path.add(CombinatorialGame.LEFT); path.add(UNCOLORED); path.add(CombinatorialGame.LEFT); path.add(UNCOLORED); path.add(CombinatorialGame.RIGHT); paths.add(path); PathMyopicCol reorderedPaths = new PathMyopicCol(paths); System.out.println("Should say true: " + multiPaths.equals(reorderedPaths)); System.out.println("Should say true: " + reorderedPaths.equals(multiPaths)); //test getPaths System.out.println("Positions as lists of integers:"); paths = onePath.getPaths(); System.out.println("Single-path position:"); for (PureLinkedList<Integer> pathList : paths) { System.out.println(pathList); } paths = multiPaths.getPaths(); System.out.println("Multi-path position:"); for (PureLinkedList<Integer> pathList : paths) { System.out.println(pathList); } //test getOptions System.out.println("Left options of single-path game: "); System.out.println("Reminder: Single-Path Game = " + onePath); for (CombinatorialGame option : onePath.getOptions(CombinatorialGame.LEFT)) { System.out.println(option); } System.out.println("Right options of single-path game: "); for (CombinatorialGame option : onePath.getOptions(CombinatorialGame.RIGHT)) { System.out.println(option); } System.out.println("Left options of multi-path game: "); for (CombinatorialGame option: multiPaths.getOptions(CombinatorialGame.LEFT)) { System.out.println(option); } System.out.println("Right options of multi-path game: "); for (CombinatorialGame option: multiPaths.getOptions(CombinatorialGame.RIGHT)) { System.out.println(option); } */ } } //end of PathMyopicCol.java