/**
 * A class that represents games of Snakes and Ladders.
 * @author *****Your name, student number and College email address****
 */
public class SnakesAndLadders
{
/* =======================================================================
       CONSTRUCTORS
   =======================================================================
*/
    /**
     * Allocates a new game of Snakes and Ladders
     * @param theWidth the width of the board (num of columns)
     * @param theHeight the height of the board (num of rows)
     * @param thePlayers the players
     */
    public SnakesAndLadders(int theWidth, int theHeight,
        Player[] thePlayers)
    {   width = theWidth;
        height = theHeight;
        generateBoard();
        players = thePlayers;
    }

/* =======================================================================
       PUBLIC INTERFACE
   =======================================================================
*/

/* --Getters----------------------------------------------------------- */

    /**
     * Returns the width of this board
     * @return the width of the board
     */
    public int getWidth()
    {   return width;
    }

    /**
     * Returns the height of the board
     * @return the height of the board
     */
    public int getHeight()
    {   return height;
    }

    /**
     * Returns the starting square of the board
     * @return the starting square of the board
     */
    public Square getStart()
    {   return start;
    }

    /**
     * Returns the players
     * @return the array of players
     */
    public Player[] getPlayers()
    {   return players;
    }

/* --Setters----------------------------------------------------------- */

    /**
     * Simulates play of the game.
     */
    public void play()
    {   Your code goes here
    }
              
/* =======================================================================
       HELPER METHODS
   =======================================================================
*/

    /**
     * Generates the board.
     * @param theWidth the width of the board
     * @param theHeight the height of the board
     */
    private void generateBoard()
    {   Square[] squares = generateSquares();
        generateSnakes(squares);
        generateLadders(squares);
    }

    /**
     * Generates the squares that make up this board, connecting them
     * in sequence.
     * @param theNumOfSquares the number of squares required
     * @return an array of the sqaures
     */
    private Square[] generateSquares()
    {   Square[] squares = new Square[width * height];
        squares[0] = new Square();
        // Loop starts at 1 because we've already generated one square
        for (int i = 1; i < squares.length; i++)
        {   squares[i] = new Square();
            squares[i - 1].linkTo(squares[i]);
        }
        start = squares[0];
        return squares;
    }

    /**
     * Generates the snakes.
     * @param theSquares an array of the squares
     */
    private void generateSnakes(Square[] theSquares)
    {   int numOfSnakes = (int) (height * SNAKE_PROBABILITY);
        int minSnakeLength = width;
        int maxSnakeLength = width * height / 2;
        int length = 0;
        int tailSquareNum = 0;
        int headSquareNum = 0;
        for (int i = 0; i < numOfSnakes; i++)
        {   do
            {   length = (int) (Math.random() * 
                    (maxSnakeLength - minSnakeLength) + 1);
                tailSquareNum =
                    (int) (Math.random() * width * height);
                headSquareNum = tailSquareNum + length;
            } while (headSquareNum >= theSquares.length - 1 ||
                 theSquares[headSquareNum].containsSnakeHead() ||
                 theSquares[headSquareNum].containsLadderFoot());
            theSquares[headSquareNum].addSnake(theSquares[tailSquareNum]);
        }
    }

    /**
     * Generates the ladders.
     * @param theSquares an array of the squares.
     */
    private void generateLadders(Square[] theSquares)
    {   int numOfLadders = (int) (height * LADDER_PROBABILITY);
        int minLadderLength = width;
        int maxLadderLength = width * height / 2;
        int length = 0;
        int footSquareNum = 0;
        int topSquareNum = 0;
        for (int i = 0; i < numOfLadders; i++)
        {   do
            {   length = (int) (Math.random() * 
                    (maxLadderLength - minLadderLength) + 1);
                footSquareNum =
                   (int) (Math.random() * width * height);
                topSquareNum = footSquareNum + length;
            } while (footSquareNum == 0 || topSquareNum > width * height - 1 ||
                 theSquares[footSquareNum].containsLadderFoot() ||
                 theSquares[footSquareNum].containsSnakeHead());
            theSquares[footSquareNum].addLadder(theSquares[topSquareNum]);
        }
    }


/* =======================================================================
       INSTANCE VARIABLES & CLASS VARIABLES
   =======================================================================
*/
    /**
     * The width of the board (num of cols)
     */
    private int width;

    /**
     * The height of the board (num of rows)
     */
    private int height;

    /**
     * The starting square
     */
    private Square start;

    /** 
     * The players
     */
    private Player[] players;

    /**
     * The probability that a row will contain a snake.
     */
    private static final float SNAKE_PROBABILITY = 0.8f;

    /**
     * The probability that a row will contain a ladder.
     */
    private static final float LADDER_PROBABILITY = 0.8f;

/* =======================================================================
       TEST DRIVER
   =======================================================================
*/
    public static void main(String[] args)
    {   Player playerA = new Player("Ann", new Dice());
        Player playerB = new Player("Bob", new Dice());
        Player playerC = new Player("Col", new Dice());
        Player[] players = {playerA, playerB, playerC};
        SnakesAndLadders sal = new SnakesAndLadders(10, 10, players);
        sal.play();
   }
}
