#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "cardstack.h"
#include "permute.h"

#ifndef NUM_CARDS
#define NUM_CARDS 60
#endif

#ifndef RACK_SIZE
#define RACK_SIZE 10
#endif

/* Set up the game state by shuffling the cards (numbered 0 through
   NUM_CARDS-1), populating the players' racks, and initializing the stock pile
   (the rest of the shuffled cards) and discard pile (from top of stock
   pile). */
void
setup_game (int racks[2][RACK_SIZE], node_t ** p_stock_pile,
	    node_t ** p_discard_pile)
{
  
} // setup_game

/* Clear the game by releasing all memory resources allocated for game play */
void
clear_game (node_t ** p_stock_pile, node_t ** p_discard_pile)
{
  
} // clear_game


/* Determine whether the given rack has "Gone Rack-O!", i.e., whether its
   contents are sorted in ascending order. */
bool
gone_racko (const int rack[RACK_SIZE])
{
  return false;
} // gone_racko


/* Print the contents of cards in the rack (with the corresponding indices) to
   the screen. */
void
print_rack (const int rack[RACK_SIZE])
{

} // print_rack


/* Get a yes or no response from a user in the form of a single typed 'y', 'Y',
   'N', or 'n' followed by a newline. Any excess input is cleared from the
   input stream up to (and including) the new line character.

   Repeats prompt and solicits input repeatedly until a valid entry is given. 

   Returns true if input is 'y' or 'Y'. 

   Exits with status EXIT_FAILURE and an error message if EOF encountered.
*/
bool
get_choice(const char * prompt)
{
  return true;
} // get_stack_choice


/* Prints a prompt for where the specified card to be inserted and returns a
   slot number in [0,RACK_SIZE-1] entered by the user. Any excess input is
   cleared from the input stream up to (and including) the new line character.

   Repeats prompt and solicits input repeatedly until a valid entry is given.

   Exits with status EXIT_FAILURE and an error message if EOF encountered.
*/
int
get_slot_number (int card)
{
  return 0;
} // get_slot_number


/* Asks the user where to insert the given card into the given rack, puts the
   given card value into the rack at that position and returns the value of the
   old card at that position. */
int
insert_card (int card, int rack[RACK_SIZE])
{
  return 0;
} // insert_card


/* Takes a card from the top of the stock pile, tells the user what they drew,
   asks whether they want to keep this card for their rack. If they do, the
   card is inserted in the user's selected position and the previous card is
   placed atop the discard pile. If they do not, the unwanted card from the
   stock is placed on the discard pile. */
void
move_from_stock (int rack[RACK_SIZE], node_t ** p_stock_pile,
		 node_t ** p_discard_pile)
{

} // move_from_stock


/* Takes the card from the top of the discard stack and inserts it into the
   rack's selected position, placing the newly evicted card from the rack atop
   the discard pile. */
void
move_from_discard (int rack[RACK_SIZE], node_t ** p_discard_pile)
{

} // move_from_discard


/* Main function for the move of one player's turn. User is informed if the
   discard pile is empty and must draw from the stock pile. Otherwise, the user
   is told the top of the discard pile and asked whether to draw from the
   discard (or else if not, they must draw from the stock pile), making the
   appropriate move (with rack insert or discard as appropriate). */
void
make_move (int rack[RACK_SIZE], node_t ** p_stock_pile,
	   node_t ** p_discard_pile)
{

} // make_move


/* General skeleton for taking turn: Prints the player's rack, makes the
   player's move, and returns whether play can continue (player has not won). */
bool game_play (int player, int rack[RACK_SIZE], node_t ** p_stock_pile,
		node_t ** p_discard_pile)
{
  assert (player==0 || player==1);
  
  return false;
} // game_play


/* Called when the main stock pile is empty. Turns the discard pile over to
   become the stock pile. For example, if the discard stack was (from top to
   bottom) [15, 42, 36, 28], the stock pile becomes [28, 36, 42, 15]. */
void
reset_stock (node_t ** p_stock_pile, node_t ** p_discard_pile)
{
  assert(  cardstack_empty(*p_stock_pile) );
  assert( !cardstack_empty(*p_discard_pile) );

  printf ("Stock pile is empty. Moving discard to pile.\n");

  // MOVE PILES HERE
  
} // reset_stock


/* Main program. Sets up game. Determines whether either player won by chance,
   then play the game for alternating players until someone wins, moving the
   discard pile when appropriate. */
#ifndef NOMAIN
int
main (void)
{
  node_t * stock_pile;
  node_t * discard_pile;
  
  int racks[2][RACK_SIZE];

  assert ( 2*RACK_SIZE < NUM_CARDS ); // Necessary for feasible game

  setup_game (racks, &stock_pile, &discard_pile);

  if (gone_racko (racks[0])) { // Check for randomly induced win
    printf ("Player 0 wins!");
    return 0;
  } else if (gone_racko (racks[1])) {
    printf ("Player 1 wins!");
    return 0;
  }

  int player = rand() % 2; // Randomly chosen first player

  // Game play loop
  while (game_play (player, racks[player], &stock_pile, &discard_pile) )
  {
    if ( cardstack_empty (stock_pile) )
      reset_stock (&stock_pile, &discard_pile);
    player = (player + 1) % 2; // Switch player
  }

  printf ("Player %d wins!\n", player);

  clear_game (&stock_pile, &discard_pile);

  return 0;
} // main
#endif
