program acm98;

(*
 * File: random.p
 * Author: Chris Alfeld (calfeld@cs.utah.edu), Jon Pabst
 *
 *  This file does absolutely everything.  Contestants, look for the section
 *  marked "MODIFY ME" and fill in the procedures there.  The part before
 *  describes/defines the data structures you should use and the part afterwards
 *  is code to handle those data structures.
 *
 *  There is a function, card_cmp, available to the contestant.  This function:
 *  card_cmp(lead_suit:lead;A,B:acm_card):integer
 *  returns 0 if the cards are equal, -1 if A<B, and 1 if A>B.
 *
 *  We will recompile this code for the contest.  Our compiler is rather
 *  picky.  It is both case sensitive and completely unaware of anything
 *  beyond standard pascal.  When in doubt use lower case.  'uses' are
 *  absolutely forbidden.
 *)

(*
 * Type for input.  The code that uses this is already written.
 *)
type
   input_array=packed array[1..32,1..20] of char;

(*
 * acm_card
 *
 * This structure describes a single card.  It is used in
 * other data structures and is the return value of PlayCard,
 * and TakeCard.
 *)
   acm_card = record
		 (*
		  * The suit of the card. 's' = spades, 'h' = hearts, 
		  * 'd' = diamonds, 'c' = clubs.		      
		  *)
		 suit:char;
		 (*
		  *  The face of the card. 'a' = ace, 'k' = king, 'q' = queen,
		  * 'j' = jack, 't' = ten, '9'-'2' = themselves.
		  *)
		 face:char;
	      end;
   
(*
 * acm_play
 *
 * This structure describes a round or partial round of plays or
 * takes.  It gives the cards played/taken by each side and which
 * side lead.  In partial rounds some cards will be not played/taken,
 * indicated by the suit and face of the card = char(32) or card = char(0).
 * The easiest test is just the expression if (ord(card)) < 33) then this
 * card does not exist.
 *)
   acm_play = record
		 (* Who lead the round.  'n','e','s' or 'w'. *)
		 leader		    : char;
		 (* The card played by each player. *)
		 north,east,south,west : acm_card;
	   end;			    

(*
 * acm_scores
 *
 * A simple structure that given the current scores of the four players.
 *)
   acm_scores = record
		   (* The score of each player *)
		   north,east,south,west : integer;
		end;			 
(*
 * acm_gameinfo
 *
 * This is the global data structure that is maintained by acm98.cpp
 * and should be read by contestant code.  It is accessible via the
 * global variables GAME.
 *)
   acm_gameinfo = record
		     (* The cards played during the last trick, and who lead. *)
		     last_trick : acm_play;

		     (* The cards taken during the current trick, and who lead.
		      * Note: 1 or more cards may be blank indicating that they
		      * will be played by or after you.  Ex: if you are the leader
		      * all four cards will be blank
		      *)
		     cur_trick : acm_play;

		     (* The cards taken is the last round of takes. *)
		     last_take : acm_play;

		     (* The cards taken in the current trick.
		      * Note: 1 or more cards may be blank.  See comment on cur_trick.
		      *)
		     cur_take : acm_play;

		     (* The size and cards of the pool.  Once all cards have been
		     * taken the size will be 0 and all cards will be blank.
		     * The cards array will be packed, i.e. as cards are removed
		     * the other cards are shifted to the front of the array to fill
		     * in the holes.
		     *)
		     pool_size : integer;
		     pool: array [1..12] of acm_card;

		     (* The size and cards of your hand.  As in the pool, the cards
		      * array is packed.
		      *)
		     hand_size : integer;
		     hand : array [1..13] of acm_card;

		     (* The current trick number.  Take numbers are indicated by
		     * -2, -1, and 0, indicating the three rounds of take.
		     *)
		     trick_number : integer;

		     (* The scores of the four players
		     * This is updated after each round is played (just before PlayCard).
		     *)
		     scores : acm_scores;

		     (* Who you are.  This is either 'n','s','e', or 'w'*)
		     player : char;
	       end;

var
   GAME :acm_gameinfo;
   INP : input_array;
   input_ind : integer;


(*
 *  MODIFY ME
 *
 *  These function should be filled in by the contestent.
 *  Each of these routines can take at most 4 seconds on a Petium 90.
 *)

(*
 * NewGame - This is called once, before anything else.  It can be
 * blank or used to set up any data structures, etc.
 *)
procedure NewGame;
begin
end;

(*
 * NewRound - This is called at the beginning of each round.  At this
 * point GAME will contain both the pool and your hand.  It can be blank.
 *)
procedure NewRound;
begin
end;

(*
 * TakeCard - This is called when the player is required to take a card.
 * It must return a valid card (a card existing in the pool).  GAME.last_take
 * and GAME.cur_take describe the last round of takes and the current round of
 * takes.  GAME.trick_number will be -2,-1, or 0 during this call.
 *)
procedure TakeCard(var card:acm_card);
begin
end;

(*
 * PlayCard - This is called when the player is required to play a card.
 * It must return a valid card (a card existing in the players hand).
 * GAME.last_trick and GAME.cur_trick describe the last trick and current
 * trick.  GAME.trick_number will be 1-13 during this call.
 *)
procedure PlayCard(var card:acm_card);
begin
end;

(*
 * EndTakes - This is called after the three round of takes have passed.
 * GAME.last_take describes the last_round of takes. 
 *)
procedure EndTakes;
begin
end;

(*
 * EndRound - This is called at the end of the round.  GAME.acm_scores are
 * the final scores for the round.  This can be blank.
 *)
procedure EndRound;
begin
end;

(*
 *  END OF MODIFY ME
 *)

(**********************************************************************)

(*
 *  The remaining code SHOULD NOT be modified.  Due to developmental concerns
 *  it is largely uncommented.  If you're really interested read the C++
 *  version to see how this all works.
 *)
function card_equals(a,b:acm_card):boolean;
begin
   card_equals:= (a.suit = b.suit) and (a.face = b.face);
end;

procedure zero_card(var card:acm_card);
begin
   card.suit:= ' ';
   card.face:= ' ';
end;

procedure zero_play(var play:acm_play);
begin
   play.leader:= ' ';
   play.north.suit:= ' ';
   play.north.face:= ' ';
   play.south.suit:= ' ';
   play.south.face:= ' ';
   play.east.suit:=  ' ';
   play.east.face:=  ' ';
   play.west.suit:=  ' ';
   play.west.face:=  ' ';
end;


procedure parse_card(var card:acm_card;suit,face:char);
begin
   card.suit:=suit;
   card.face:=face;
end;

procedure parse_play(var play:acm_play);
var
   who:char;
   card:packed array[1..3]of char;

begin
   zero_play(play);
   who := INP[input_ind,1];
   input_ind:=input_ind+1;
   play.leader:=who;
   while true do begin
      card[1]:=INP[input_ind,1];
      card[2]:=INP[input_ind,2];
      input_ind:=input_ind+1;
      if (ord(card[1]) < 33) then exit;
      case (who) of
	'n' :
	parse_card(play.north,card[1],card[2]);
	'e' :
	parse_card(play.east,card[1],card[2]);
	's' :
	parse_card(play.south,card[1],card[2]);
	'w' :
	parse_card(play.west,card[1],card[2]);
      end;
      who := INP[input_ind,1];
      input_ind:=input_ind+1;
   end;
end;

procedure client_take(card:acm_card);
begin
   GAME.hand[GAME.hand_size+1]:=card;
   GAME.hand_size:=GAME.hand_size+1;

   writeln(card.suit,card.face);
end;

procedure client_play(card:acm_card);
var
   card_loc:integer;

begin
   card_loc:=1;
   while (card_loc <= GAME.hand_size)and
      not(card_equals(GAME.hand[card_loc],card)) do card_loc:=card_loc+1;
   for card_loc:=card_loc to GAME.hand_size-1 do
      GAME.hand[card_loc]:=GAME.hand[card_loc+1];
   GAME.hand_size:=GAME.hand_size-1;

   writeln(card.suit,card.face);
end;

procedure round_start;
var
   loop_var:integer;
   card_string : packed array[1..3]of char;
begin
   zero_play(GAME.last_trick);
   zero_play(GAME.cur_trick);
   zero_play(GAME.last_take);
   zero_play(GAME.cur_take);
   GAME.pool_size:=12;
   GAME.hand_size:=10;
   for loop_var:=1 to 13 do
      zero_card(GAME.hand[loop_var]);
   GAME.trick_number:=-3;
   GAME.scores.north:=0;
   GAME.scores.south:=0;
   GAME.scores.east:=0;
   GAME.scores.west:=0;

   card_string[2]:= ' ';

   GAME.player := INP[input_ind,1];
   input_ind:=input_ind+1;
   for loop_var:=1 to 10 do begin
      card_string[1] := INP[input_ind][1];
      card_string[2] := INP[input_ind][2];
      input_ind:=input_ind+1;
      parse_card(GAME.hand[loop_var],card_string[1],card_string[2]);
   end;
   for loop_var:=1 to 12 do begin
      card_string[1] := INP[input_ind][1];
      card_string[2] := INP[input_ind][2];
      input_ind:=input_ind+1;
      parse_card(GAME.pool[loop_var],card_string[1],card_string[2]);
   end;

   NewRound;
end;

procedure trim_pool(play : acm_play);
var
   card_loc:integer;
   last_card:integer;

begin

   for card_loc:=1 to GAME.pool_size do
      if (card_equals(GAME.pool[card_loc],play.north) or
	  card_equals(GAME.pool[card_loc],play.east) or
	  card_equals(GAME.pool[card_loc],play.south) or
	  card_equals(GAME.pool[card_loc],play.west)) then
	 zero_card(GAME.pool[card_loc]);

   last_card:=GAME.pool_size;
   while (ord(GAME.pool[last_card].suit) < 33) do
      last_card:=last_card-1;


   card_loc := 1;
   while (card_loc < last_card) do begin
      if (ord(GAME.pool[card_loc].suit) < 33) then
      begin
	 GAME.pool[card_loc]:=GAME.pool[last_card];
	 while (last_card > card_loc) and (GAME.pool[last_card].suit = ' ') do
	    last_card:=last_card - 1;
      end;
      card_loc := card_loc + 1;
   end;

   GAME.pool_size:=0;
   while ord(GAME.pool[GAME.pool_size+1].suit) > 32 do
      GAME.pool_size := GAME.pool_size + 1;
end;


procedure pool_take;
var
   card:acm_card;
begin
   GAME.trick_number:=GAME.trick_number+1;

   parse_play(GAME.cur_take);
   trim_pool(GAME.cur_take);

   TakeCard(card);

   client_take(card);
end;

procedure take_result;
begin
   parse_play(GAME.last_take);
   trim_pool(GAME.last_take);

   if (GAME.trick_number = 0) then
      EndTakes;
end;

procedure play_hand;
var
   card:acm_card;
begin
   GAME.trick_number:=GAME.trick_number+1;

   parse_play(GAME.cur_trick);

   PlayCard(card);
   client_play(card);
end;

function card_cmp(lead_suit:char;A, B:acm_card):integer;
var
   A_val, B_val	: integer;
   card_values	: packed array[1..14] of char;

begin
   card_values := '_23456789tjqka';
   A_val:=0;
   B_val:=0;
   
   if (A.suit = lead_suit) then begin
      while (A.face <> card_values[A_val]) and (A_val<14) do A_val:=A_val+1;
   end;


   if (B.suit = lead_suit) then begin
      while (B.face <> card_values[B_val])and(B_val<14) do B_val:=B_val+1;
   end;

   if (A_val = B_val) then card_cmp:= 0;
   if (A_val < B_val) then card_cmp:=-1;
   if (A_val > B_val) then card_cmp:= 1;
end;

procedure trick_result;
var
   took_trick:char;
   cards:array[1..4]of acm_card;
   highest:acm_card;
   play_table:packed array[1..4]of char;
   loop_var:integer;
   score:integer;
   lead_suit:char;

begin

   took_trick:='n';
   highest:=GAME.last_trick.north;
   play_table:= 'nesw';
   score:=0;

   parse_play(GAME.last_trick);

   cards[1]:=(GAME.last_trick.north);
   cards[2]:=(GAME.last_trick.east);
   cards[3]:=(GAME.last_trick.south);
   cards[4]:=(GAME.last_trick.west);

   case (GAME.last_trick.leader) of
     'n':lead_suit:=GAME.last_trick.north.suit;
     'e':lead_suit:=GAME.last_trick.east.suit;
     's':lead_suit:=GAME.last_trick.south.suit;
     'w':lead_suit:=GAME.last_trick.west.suit;
   end;

   for loop_var:=2 to 4 do
      if (card_cmp(lead_suit,
	  (cards[loop_var]),
	  highest) = 1) then begin
	     highest:=cards[loop_var];
	     took_trick:=play_table[loop_var];
	  end;

   if (GAME.trick_number = 1) or (GAME.trick_number = 13) then
      score := 3
   else
      score := 1;
   for loop_var:=1 to 4 do
      if (cards[loop_var].face = '8') then
	 score:=score+2;

   case took_trick of
     'n':
     GAME.scores.north := GAME.scores.north+score;
     'e':
     GAME.scores.east := GAME.scores.east+score;
     's':
     GAME.scores.south := GAME.scores.south+score;
     'w':
     GAME.scores.west := GAME.scores.west+score;
   end;
end;

procedure round_end;
begin
   EndRound;
end;


function get_string(var s:input_array):integer;
var
   i,j,p     : integer;
   in_string : boolean;
   inword    : packed array [1..200] of char;
begin
   for i:=1 to 32 do
      for j:=1 to 20 do
	 s[i,j]:= ' ';

   for p := 1 to 200 do
      inword[p]:= ' ';
   
   readln (inword);
   
   in_string:=false;
   i:=0;
   j:=0;
   
   for p := 1 to 200 do
   begin
      if (ord(inword[p]) < 33) then
      begin
	 in_string := false;
      end else begin
	 if (in_string) then begin
	    s[i,j]:=inword[p];
	    j:=j+1;
	 end else begin
	    in_string := true;
	    i:=i+1;
	    j:=2;
	    s[i,1]:=inword[p];
	 end;
      end;
   end;

   (* Debug output which prints each word on a line.
   for p := 1 to i do
   begin
      write (p);
      write (' ');
      for j := 1 to 20 do
      begin
	 write (s[p][j]);
      end;
      writeln (' ');
   end;
  *)
    
   get_string:=i;
end;

begin
   NewGame;

   while (get_string(INP) <> 0) do
   begin
      input_ind:=2;
      case INP[1,1] of
	's' : round_start;
	't' : pool_take;
	'a' : take_result;
	'p' : play_hand;
	'r' : trick_result;
	'e' : round_end;
	'*' : INP[1,1] := INP[1,1];  (* Dummy statement. *)
      end;
      flush(output);
   end;
end.




