import java.lang.*; import java.io.*; import java.util.*; /** * Models a position of the game Antonim. It's just like Nim, except that copies of piles are lost. So the position {1, 1, 4} is not an option of {1, 2, 4}. * * @author Kyle Burke <paithanq@gmail.com> */ public class Antonim extends CombinatorialGame { // extends ImpartialGame<Antonim> { //instance variables //the piles in this. private PureSet<Integer> piles; /** * Creates a new Antonim position. * * @param piles A PureSet of piles. All piles must be greater than zero, or an IllegalArgumentException will be thrown. */ public Antonim(PureSet<Integer> piles) throws IllegalArgumentException { List<Integer> pileList = piles.toList(); for (Integer pile : pileList) { if (pile.intValue() < 1) { throw new IllegalArgumentException("Tried to create a Antonim with non-positive piles: " + piles); } } this.piles = piles; } /** * Gets a String representation. * * @return A String representation of this. */ public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Antonim: {"); List<Integer> pileSizes = this.piles.toList(); for (Integer pile : pileSizes) { builder.append(pile + " "); } if (pileSizes.size() > 0) { builder.deleteCharAt(builder.length() -1); } builder.append("}"); return builder.toString(); } /** * Gets the piles. * * @return The piles of this PureSet. We don't need to copy it because it's immutable! */ public PureSet<Integer> getPiles() { return this.piles; } /** * Returns a version of this with the piles in order from lowest to highest. */ public Antonim canonize() { List<Integer> piles = this.getPiles().toList(); Collections.sort(piles); return new Antonim(new PureSet<Integer>(piles)); } /** * Clones this. * * @return A deep clone of this. */ public Antonim clone() { return new Antonim(this.getPiles()); } @Override public boolean equals(Object other) { if ((other == null) || (other.getClass() != this.getClass())) { return false; } else { return this.equals((CombinatorialGame) other); } } @Override public boolean equals(CombinatorialGame other) { if ((other == null) || (other.getClass() != this.getClass())) { return false; } else { Antonim otherNim = (Antonim) other; return this.getPiles().equals(otherNim.getPiles()); } } @Override public Collection<CombinatorialGame> getOptions(int playerId) { return this.getOptions(); } //@Override public Collection<CombinatorialGame> getOptions() { ArrayList<CombinatorialGame> options = new ArrayList<CombinatorialGame>(); PureSet<Integer> piles = this.getPiles(); List<Integer> pileList = piles.toList(); if (pileList.isEmpty()) { return options; } for (Integer pile : pileList) { ArrayList<Integer> singletonList = new ArrayList<Integer>(); singletonList.add(pile); PureSet<Integer> pilesWithoutPile = piles.differenceWith(new PureSet<Integer>(singletonList)); Antonim option = new Antonim(pilesWithoutPile); if (!options.contains(option)) { options.add(option); } for (int i = 1; i < pile.intValue(); i++) { singletonList = new ArrayList<Integer>(); singletonList.add(new Integer(i)); option = new Antonim(pilesWithoutPile.unionWith(new PureSet<Integer>(singletonList))); if (!options.contains(option)) { options.add(option); } } } return options; } /** * A generator of Antonim positions. */ public static class PositionBuilder implements PositionFactory<Antonim> { //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 PositionBuilder(int numPiles, int maxPileSize) { this.numPiles = numPiles; this.maxPileSize = maxPileSize; } //@override public Antonim getPosition() { ArrayList<Integer> piles = new ArrayList<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 Antonim(new PureSet<Integer>(piles)); } } //end of PositionBuilder /* Private methods */ /* Unit test! */ /** * Unit test for Antonim. */ public static void main(String[] args) { //test the constructor and toString LinkedList<Integer> piles = new LinkedList<Integer>(); piles.add(new Integer(3)); piles.add(new Integer(1)); piles.add(new Integer(5)); piles.add(new Integer(7)); Antonim nim = new Antonim(new PureSet<Integer>(piles)); System.out.println("Position: " + nim); //test that the piles are still in working order System.out.println("Piles used to create the position: " + piles); //test the constructor again on an illegal pile size piles.add(new Integer(-8)); try { Antonim illegal = new Antonim(new PureSet<Integer>(piles)); } catch (IllegalArgumentException iae) { System.out.println("Couldn't create a game!"); } piles.remove(new Integer(-8)); //test the constructor with multiple elements in the list piles.add(new Integer(5)); Antonim nimCopy = new Antonim(new PureSet<Integer>(piles)); //test getPiles System.out.println("The piles: " + nim.getPiles()); //test clone Antonim clone = (Antonim) nim.clone(); System.out.println("Clone: " + clone); //make sure the original position is still intact System.out.println("Position again: " + nim); //test equals //easy true test System.out.println("position equals clone? (should be true): " + nim.equals(clone)); System.out.println("clone equals position? (should be true): " + clone.equals(nim)); //set up and test a complex false test piles.add(4); Antonim bigger = new Antonim(new PureSet<Integer>(piles)); System.out.println("position equals bigger? (should be false): " + nim.equals(bigger)); System.out.println("bigger equals position? (should be false): " + bigger.equals(nim)); //set up and test a complex true test System.out.println("position equals copy? (should be true): " + nim.equals(nimCopy)); System.out.println("copy equals position? (should be true): " + nimCopy.equals(nim)); //test getOptions System.out.println("Options:"); for (CombinatorialGame option: nim.getOptions(CombinatorialGame.LEFT)) { System.out.println(" " + option); } } } //end of Antonim