/**
 * Represents the game (ruleset) Elephants and Rhinos.  The Left player moves the Elephants, the Right player moves the Rhinos.
 * 
 * @author Kyle Burke <paithanq@gmail.com>
 * 
 */
//package something;
 
import java.lang.*;
import java.io.*;
import java.util.*;

public class ElephantsAndRhinos extends CombinatorialGame {

    //instance variables
    
    private ArrayList<String> spaces;
    
    //constants
    
    /**
     * The String that indicates an Elephant.
     */
    public static final String ELEPHANT = "E";
    
    /**
     * The String that indicates a Rhino.
     */
    public static final String RHINO = "R";
    
    /**
     * The String that indicates neither an elephant nor a rhino.
     */
    public static final String EMPTY = " ";
    
    /** Constructors **/
    
    /**
     * Creates a 
     *
     * @param spaces  An ArrayList of the different positions of pachyderms.  Each element must be either "E", "R", or " ".
     * @throws IllegalArgumentException  If any element in spaces is not a legal string.
     */
    public ElephantsAndRhinos(ArrayList<String> spaces) {
        this.spaces = new ArrayList<String>();
        for (String pachyderm : spaces) {
            if (pachyderm.length() != 1 || !(ELEPHANT + RHINO + EMPTY).contains(pachyderm)) {
                throw new IllegalArgumentException("Argument contains " + pachyderm + ", which is not a legal string for a space!");
            }
            this.spaces.add(pachyderm);
        }
    }
    
    //public methods
    
    //@override 
    public Collection<CombinatorialGame> getOptions(int player) {
        Collection<CombinatorialGame> options = new ArrayList<CombinatorialGame>();
        
        for (int i = 0; i < this.spaces.size(); i++) {
            if (this.spaces.get(i).equals(ELEPHANT) && player == CombinatorialGame.LEFT) {
                if (i + 1 < this.spaces.size() && this.spaces.get(i+1).equals(EMPTY)) {
                    //add a move for Left
                    ElephantsAndRhinos option = (ElephantsAndRhinos) this.clone();
                    option.spaces.set(i, EMPTY);
                    option.spaces.set(i+1, ELEPHANT);
                    options.add(option);
                }
            } else if (this.spaces.get(i).equals(RHINO) && player == CombinatorialGame.RIGHT) {
                if (i > 0 && this.spaces.get(i-1).equals(EMPTY)) {
                    //add a move for Right
                    ElephantsAndRhinos option = (ElephantsAndRhinos) this.clone();
                    option.spaces.set(i, EMPTY);
                    option.spaces.set(i-1, RHINO);
                    options.add(option);
                }
            }
        }
        
        return options;
    }
    
    /**
     * Returns the name of this game.
     * 
     * @return  The String "Elephants and Rhinos".
     */
    public static String getName() {
        return "Elephants and Rhinos";
    }
    
    /**
     * Returns the spaces.
     *
     * @return  An ArrayList representation of this, with Strings for each element.  (This is a deep copy of the list used in the constructor.)
     */
    public ArrayList<String> getSpaces() {
        ArrayList<String> spacesCopy = new ArrayList<String>();
        for (String pachyderm : this.spaces) {
            spacesCopy.add(pachyderm);
        }
        return spacesCopy;
    }
    
    /**
     * Returns a deep clone of this.
     *
     * @return  A deep clone of this position.
     */
    public CombinatorialGame clone() {
        return new ElephantsAndRhinos(this.spaces);
    }
    
    //@override
    public boolean equals(Object obj) {
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        ElephantsAndRhinos other = (ElephantsAndRhinos) obj;
        return this.equals(other);
    }
    
    //@override
    public boolean equals(CombinatorialGame other) {
        return this.equals((Object) other);
    }
    
    /**
     * Returns whether this equals another position.
     *
     * @param other     Another position.
     * @return          Whether this position equals the other.  This should compare identity, *NOT* equivalence.
     */
    public boolean equals(ElephantsAndRhinos other) {
         return this.spaces.equals(other.spaces);
    }
    
    
    //@override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("[");
        for (String pachyderm : this.spaces) {
            builder.append(" " + pachyderm + " |");
        }
        if (builder.length() == 1) {
            builder.append("]");
        } else {
            builder.setCharAt(builder.length() - 1, ']');
        }
        return builder.toString();
    }
    
    /**
     * Generator for Elephants and Rhinos positions.
     */
    public static class PositionBuilder implements PositionFactory<ElephantsAndRhinos> {
        //max length of the board
        private int maxBoardSize;
        
        //probability each space will have an elephant or rhino
        private double density;
        
        /**
         * Constructor
         * @param maxBoardSize  The maximum number of spaces in the board.
         * @param density  The probability that each space will have an elephant or rhino.
         */
        public PositionBuilder(int maxBoardSize, double density) {
            this.maxBoardSize = maxBoardSize;
            this.density = density;
        }
        
        /**
         * Generate a position!
         *
         * @return  A new ElephantsAndRhinos position.
         */
        public ElephantsAndRhinos getPosition() {
            Random random = new Random();
            int boardSize = random.nextInt(this.maxBoardSize + 1);
            ArrayList<String> board = new ArrayList<String>();
            for (int i = 0; i < boardSize; i++) {
                if (random.nextDouble() < this.density) {
                    //add a pachyderm
                    if (random.nextDouble() < .5) {
                        board.add(ELEPHANT);
                    } else {
                        board.add(RHINO);
                    }
                } else {
                    //add an empty space
                    board.add(EMPTY);
                }
            }
            return new ElephantsAndRhinos(board);
        }
    
    } //end of ElephantsAndRhinos.PositionBuilder
    
    /**
     * Main method for testing.
     */
    public static void main(String[] args) {
        PositionFactory<ElephantsAndRhinos> factory = new ElephantsAndRhinos.PositionBuilder(20, .3);
        ElephantsAndRhinos game = factory.getPosition();
        System.out.println("game: " + game);
        System.out.println("\nOptions for Left from \n" + game + ": \n - - - - - - - - - - - - - - - - - - - ");
        for (CombinatorialGame option : game.getOptions(CombinatorialGame.LEFT)) {
            System.out.println(option + "; ");
        }
        System.out.println("\nOptions for Right from \n" + game + ": \n - - - - - - - - - - - - - - - - - - - ");
        for (CombinatorialGame option : game.getOptions(CombinatorialGame.RIGHT)) {
            System.out.println(option + "; ");
        }
    }
   
   
} //end of ElephantsAndRhinos.java