/** * Models a Rotisserie Nim position. * * @author Kyle Burke <paithanq@gmail.com> */ import java.lang.*; import java.io.*; import java.util.*; public class RotisserieNim extends CombinatorialGame { //instance variables //the piles in this. private PureQueue<Integer> piles; /** * Class constructor. * * @param piles An array of the pile sizes for this game. The zeroeth element is the first pile that will be played on. */ public RotisserieNim(int[] piles) { //cheating here, using a built-in class for testing this.piles = new PureQueue<Integer>(); for (int i = 0; i < piles.length; i++) { int pileSize = piles[i]; if (pileSize > 0) { this.piles.add(new Integer(pileSize)); } else { System.err.println("Tried to add a new pile with " + pileSize + " sticks."); } } } /** * Class constructor. * * @param piles An array of the pile sizes for this game. The zeroeth element is the first pile that will be played on. */ public RotisserieNim(Integer[] piles) { this(RotisserieNim.unboxArray(piles)); } /** * Class constructor. * * @param piles A Queue of the piles sizes for this game. */ public RotisserieNim(PureQueue<Integer> piles) { this.piles = this.copyQueue(piles); } /** * Gets a String representation. * * @return A String representation of this. */ public String toString() { String string = "A Rotisserie Nim position: Next Pile -->"; List<Integer> pileSizes = getListFromQueue(this.getPiles()); for (Integer pileSize : pileSizes) { string += " " + pileSize; } string += " <-- Last Pile"; return string; } /** * Gets the piles. * * @return A copy of the piles, as a Queue. */ public PureQueue<Integer> getPiles() { return this.copyQueue(this.piles); } /** * Clones this. * * @return A deep clone of this. */ public RotisserieNim clone() { return new RotisserieNim(this.piles); } @Override public boolean equals(CombinatorialGame game) { try { RotisserieNim otherNim = (RotisserieNim) game; return this.piles.equals(otherNim.piles); } catch (ClassCastException cce) { return false; } } @Override public boolean equals(Object obj) { RotisserieNim otherNim; try { otherNim = (RotisserieNim) obj; return this.piles.equals(otherNim.piles); } catch (ClassCastException cce) { return false; } } //@override public Collection<CombinatorialGame> getOptions(int player) { Collection<CombinatorialGame> options = new Vector<CombinatorialGame>(); int firstPileSize; try { firstPileSize = this.piles.element().intValue(); } catch (NoSuchElementException nsee) { //there are no piles; there is no first pile! return options; } //create the option that removes all RotisserieNim takeAll = this.clone(); takeAll.piles.remove(); options.add(takeAll); for (int optionPileSize = 1; optionPileSize < firstPileSize; optionPileSize++) { //add an option with the new pile on the end RotisserieNim newOption = takeAll.clone(); newOption.piles.add(new Integer(optionPileSize)); options.add(newOption); } return options; } /** * Unit test for RotisserieNim. */ public static void main(String[] args) { int[] piles = new int[] {3, 5, 7}; RotisserieNim cycleNim = new RotisserieNim(piles); System.out.println("Position: " + cycleNim); System.out.println("Clone: " + cycleNim.clone()); System.out.println("Options:"); for (CombinatorialGame option: cycleNim.getOptions(CombinatorialGame.LEFT)) { System.out.println(" " + option); } } /* Private methods */ //"unboxes" a list of integers. More specifically, returns a primitive copy of a list of Integer objects. private static int[] unboxArray(Integer[] integers) { int[] integersUnboxed = new int[integers.length]; for (int i = 0; i < integers.length; i++) { integersUnboxed[i] = integers[i].intValue(); } return integersUnboxed; } //copies a Queue of Integers private <T> PureQueue<T> copyQueue(PureQueue<T> elements) { PureQueue<T> copyToReturn = new PureQueue<T>(); PureQueue<T> copyToReuse = new PureQueue<T>(); //remove all elements of integers and add to both copies while (true) { T nextElement; try { nextElement = elements.remove(); copyToReturn.add(nextElement); copyToReuse.add(nextElement); } catch (NoSuchElementException nsee) { break; //escape the while loop; we've removed all elements } } //elements is now empty! Leave copyToReturn as is, but let's put the things from copyToReuse back into elements. while (true) { T nextElement; try { nextElement = copyToReuse.remove(); elements.add(nextElement); } catch (NoSuchElementException nsee) { break; //escape the loop; we've remove everything from copyToReuse } } return copyToReturn; } //returns an ArrayList version of a Queue private <T> ArrayList<T> getListFromQueue(PureQueue<T> queue) { PureQueue<T> queueCopy = this.copyQueue(queue); ArrayList<T> list = new ArrayList<T>(); while (true) { T nextElement; try { nextElement = queueCopy.remove(); list.add(nextElement); } catch (NoSuchElementException nsee) { break; //escape the loop; we've remove everything from copyToReuse } } return list; } /** * A generator of RotisserieNim positions. */ public static class RotisserieFactory implements PositionFactory<RotisserieNim> { //maximum number of piles it will generate private int numPiles; //maximum piles size private int maxPileSize; /** * Class constructor. * * @param numPiles The maximum number of piles. * @param maxPileSize The maximum size of a pile. */ public RotisserieFactory(int numPiles, int maxPileSize) { this.numPiles = numPiles; this.maxPileSize = maxPileSize; } //@override public RotisserieNim getPosition() { PureQueue<Integer> piles = new PureQueue<Integer>(); Random randomGenerator = new Random(); for (int i = 0; i < numPiles; i++) { int pileSize = randomGenerator.nextInt(this.maxPileSize + 1); if (pileSize > 0) { piles.add(new Integer(pileSize)); } } return new RotisserieNim(piles); } } //end of RotisserieFactory } //end of RotisserieNim