head	1.5;
access;
symbols
	tonic_4:1.5
	tonic_3:1.5
	tonic_2:1.5
	demo:1.5.0.2
	design_report:1.5
	oral_presentation_freeze:1.3.0.2
	DAVEG_CDP:1.1.0.2;
locks; strict;
comment	@ * @;


1.5
date	95.12.01.05.10.14;	author hartmans;	state Exp;
branches;
next	1.4;

1.4
date	95.12.01.03.39.16;	author hartmans;	state Exp;
branches;
next	1.3;

1.3
date	95.11.30.07.16.25;	author jered;	state Exp;
branches
	1.3.2.1;
next	1.2;

1.2
date	95.11.28.03.01.48;	author jered;	state Exp;
branches;
next	1.1;

1.1
date	95.11.26.04.20.25;	author jered;	state Exp;
branches;
next	;

1.3.2.1
date	95.11.30.08.35.27;	author hartmans;	state Exp;
branches;
next	1.3.2.2;

1.3.2.2
date	95.11.30.08.49.54;	author jered;	state Exp;
branches;
next	1.3.2.3;

1.3.2.3
date	95.11.30.09.25.32;	author hartmans;	state Exp;
branches;
next	1.3.2.4;

1.3.2.4
date	95.11.30.10.03.15;	author hartmans;	state Exp;
branches;
next	1.3.2.5;

1.3.2.5
date	95.12.01.02.33.22;	author jered;	state Exp;
branches;
next	;


desc
@@


1.5
log
@Fix tic_board assertions
@
text
@// $Id: tic_board.C,v 1.4 1995/12/01 03:39:16 hartmans Exp $
#include <game.h>
#include <move.h>
#include <ps5/error_response.h>
#include "tic_board.h"
#include <player.h>

//CLASS tic_move BEGINS
class tic_move: public move {
// Overview:  This abstraction, a subclass of the generic move, represents a
// player 'move' in the game of tic-tac-toe.  A move in the game of tic-tac-toe
// is the placement of either an X or an O in one of the 9 squares that make
// up the playing field.

// Abstraction Fn: tpiece is the tic_board::tic_piece placed (only X and O
// are valid; a player may not place the empty piece); txpos and typos are
// the X and Y coordinates of the placed piece. ([0,0] is the upper-left
// square of the playing board.)

// Rep Invariant:  this must be a valid tic_move as defined by the abstraction
// fn; that is tpiece must be an x_piece or o_piece, and txpos and typos must
// be valid board coordinates. 
public:
  tic_move(tic_board::tic_piece cpiece, int xpos, int ypos) {
  // Overview: The move subclass-specific constructor.
  // Checks: cpiece is an X or an O, 0 < xpos, ypos <= 2
  // Effects: Creates a move corresponding to placing cpiece at xpos, ypos.
    check((0 <= xpos) && (xpos <=2), "tic_move: Invalid xpos!");
    check((0 <= ypos) && (ypos <=2), "tic_move: Invalid ypos!");
    check((cpiece == tic_board::x_piece) || (cpiece == tic_board::o_piece), 
	  "tic_move: Invalid piece!");  // Placing a blank piece isn't a move
    tpiece = cpiece;
    txpos  = xpos;
    typos  = ypos;    // Uh, that's t-ypos, not typos.
  }   

  tic_move(const tic_move &m) {
  // Overview: The tic_move copy constructor. Creates an independent duplicate
  // of m.
    tpiece = m.tpiece;
    txpos = m.txpos;
    typos = m.typos; 
  }    // Copy move. I hope.

  virtual ~tic_move(){};
  
    virtual void display(extensions *, ostream& body) {
  // Effects: Sends a move representation to the ostream body.
    body << "put a " << tic_board::piece_to_name(tpiece) << " at ["
      << txpos << "," << typos << "]"; }

  virtual bool operator==(move &m) {
  // Overview: virtual move equality. If m's subclass is that of this, then
  // compares rep, otherwise returns false.
  // Effects: Returns true if the moves are identical, false otherwise.
    tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
    if (!ptr) return false;               // They're not even the same type...
    return ((tpiece == ptr->tpiece) && (txpos == ptr->txpos) && 
	    (typos == ptr->typos));
  }          

  virtual move* copy() {
  // Overview: Dups a tic_move. This allows the copy method to work in the
  // virtual class move.
  // Effects: Returns a heap copy of this move.
    return new tic_move(*this); }

  virtual void* force(typeinfo_t &type) {
    if (type == typeinfo) return this;
    else return 0; }

  tic_move& operator=(const tic_move& m) {
  // Modifies: this
  // Effects: this becomes m
    tpiece = m.tpiece;
    txpos = m.txpos;
    typos = m.typos; 
    return *this; }

  // Overview: Public methods to retrieve tic_move specific information.
  tic_board::tic_piece get_piece() {
    return tpiece; }         // Return piece type

  int get_xpos() {
    return txpos; }          // Return x position

  int get_ypos() {
    return typos; }          // Return y position

  static typeinfo_t typeinfo;

private:
  tic_board::tic_piece tpiece;    // The piece placed
  int txpos, typos;               // The location tpiece is placed
};

typeinfo_t tic_move::typeinfo = new_typeinfo(); 
// Initializes tic_move's typeinfo
//CLASS tic_move ENDS

//CLASS tic_move_gen BEGINS
class tic_move_gen : public move_generator {
// Overview: This creates a move_generator that iterates over all valid moves
// for a given player and board. Neither the board nor player may change while
// the generator is in use. The player's position, and the piece corresponding
// to that position may not change, as well.

public:
  tic_move_gen(int p, tic_board *cboard) {
  // Requires: cboard doesn't change while the generator is in use.
  // Effects: constructs a generator that returns the valid moves.
    tx = 0; ty = 0;     // Reset generator
    tboard = cboard;    // Squirrel away our construction data
    ppiece = tic_board::player_to_piece(p);
    tplayer = p; }
  
  virtual bool get(move *&m) {
  // Modifies: this
  // Effects:  If more moves remain, returns true and sets m to be a pointer
  // to the next move, else returns false.
  // FIXME This routine is memory 'leaky'
    if (ty > 2) return false;  // Whoops! That's all, folks!
    m=new tic_move(ppiece,tx,ty);
    while (!tboard->is_legal_move(*m,tplayer)) {
      tx++;                      // Advance to the next move
      if (tx > 2) { tx = 0; ty++; }
      if (ty > 2) return false;  // Whoops! That's all, folks!
      m=new tic_move(ppiece,tx,ty);
    }
    tx++;                      // Advance to the next move
    if (tx > 2) { tx = 0; ty++; } 
    return true; }

private:
  tic_board *tboard;              // The board we are iterating over
  int tx, ty;                     // Our current position on (or off) the board
  int tplayer;                    // The player we are generating moves for
    tic_board::tic_piece ppiece;     // Tplayer's piece type
};
//CLASS tic_move_gen ENDS

tic_board::tic_board(){
// Effects: Initializes the state of tic_board on creation.
  array<tic_piece> atmp;

  for (int i=0; i <=  2; i++) {             // Create the tic_board, fill with
    board_rep.append(atmp);               // no_pieces.
    for (int j=0; j <= 2; j++) 
      board_rep[i].append(no_piece);
  }
  won_player = -1;                        // No player has won
  turn_token = 0;                         // X goes first
}

bool tic_board::is_legal_move(move &m, int p) const {
// Checks: Player must have a position.
  if (won_player != -1) return false;  // The game is over
  tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
  if (!ptr) return false;        // I can't use this move here
  if (player_to_piece(p) != ptr->get_piece())
       return false;
  if (p != turn_token) return false;  // It's not p's turn 
  if (board_rep[ptr->get_xpos()][ptr->get_ypos()] == no_piece)
    return true;                // Is the square empty?  
  else return false;            
}

game::move_result tic_board::apply(move &m, int p) {
  tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
  if (!ptr) return game::move_invalid; // I can't use this move here
  if (!is_legal_move(m, p))
    return game::move_invalid;         // That move was invalid
  board_rep[ptr->get_xpos()].store(ptr->get_ypos(),ptr->get_piece());
  if (won_player == -1)                // Check and see if p just won
    won_player = this->check_for_winner();
  turn_token=1-turn_token;
  return game::ok;                     // Move applied.
}

bool tic_board::unapply(move &m, int ) {
    tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
    if (!ptr) return false;
    won_player = -1;  
    turn_token=1-turn_token;
    board_rep[ptr->get_xpos()].store(ptr->get_ypos(),no_piece);  
  return true; }

int tic_board::winner() {
  return won_player;}

http_response* tic_board::get(string request, extensions *extras){
  return new error_response(http_response::OK,
			    "tic_board::get unimplemented."); }

//FIXME This should probably say whose turn it is
void tic_board::display(extensions *ext, ostream& body, int player_num)const {
  body << "<H2>The current game board:</H2>" << endl;
  for (int i=0; i <= 2; i++) {
      for (int j=0; j <= 2; j++)
      body << piece_to_name(board_rep[j][i]) << " ";
    body << "<P>" << endl;
  }
}

bool tic_board::valid_move_available(int p) const {
// Effects: returns true if player p has any current legal moves,
// returns true, else returns false.
  move_generator* mg = new tic_move_gen(p, (tic_board *) this); 
move *foo;
  bool retval=mg->get(foo);
  delete mg;
  return retval;
}

move_generator* tic_board::valid_moves(int p) const{
  return new tic_move_gen(p, (tic_board *) this); }

board::value tic_board::eval_move_delta(move &m, int p) const {
  tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
  if (!ptr) return 0;          // I can't use this move here
  if (!is_legal_move(m, p))
    return 0;                  // That move was invalid
//FIXME: Write this
// See if this move:
//   Wins the game: 10
//   Allows opponent to win next move: -10
//   Everything else: 0 (We're quite simplistic here.)
  return 0; //Temporary
}

board::value tic_board::evaluate(int p) const {
//FIXME: Write this
// See if:
//   p can win in one move: 10
//   !p can win in one move: -10
//   Else: 0
  return 0; //Temporary
}

board* tic_board::clone() const {
  tic_board *tb = new tic_board();
  board::clone_part(*tb);
  clone_part(*tb);
}

void tic_board::clone_part(tic_board &b) const {
  b.won_player = won_player;
  b.turn_token = turn_token;
  b.board_rep = board_rep;
}

void* tic_board::force(typeinfo_t &t){
  if (t == typeinfo) return this;
  else return 0;
}

char tic_board::piece_to_name(tic_piece cpiece) {
  switch (cpiece) {
  case no_piece:
    return '_';
    
  case x_piece:
    return 'X';
    
  case o_piece:
    return 'O';
  };
  abort();
}

tic_board::tic_piece tic_board::player_to_piece(int p) {
  if (p == 0) return x_piece;
  if (p == 1) return o_piece;
  return no_piece;
}

int tic_board::piece_to_player(tic_piece t) {
  if (t == x_piece) return 0;
  if (t == o_piece) return 1;
  return -1;
}

int tic_board::check_for_winner() {
// Effects: Returns the winner of this if a player has won, -1 if nobody has
//  won, -2 is there is a draw.  The return value is undefined if more than
// one player can be considered to have won.
  for (int i=0; i<=2; i++) {
    tic_piece winpiece=board_rep[i][0];
    bool twin=true;
    for (int j=1; j<=2; j++)
      if (board_rep[i][j] != winpiece)
	twin=false;
    if (twin && (winpiece != no_piece))
      return piece_to_player(winpiece);
  }
  for (int i=0; i<=2; i++) {
    tic_piece winpiece=board_rep[0][i];
    bool twin=true;
    for (int j=1; j<=2; j++)
      if (board_rep[j][i] != winpiece)
	twin=false;
    if (twin && (winpiece != no_piece))
      return piece_to_player(winpiece);
  }
  tic_piece winpiece=board_rep[0][0];
  bool twin=true;
  for (int j=1; j<=2; j++)
    if (board_rep[j][j] != winpiece)
      twin=false;
  if (twin && (winpiece != no_piece))
    return piece_to_player(winpiece);
  winpiece=board_rep[0][2];
  twin=true;
  for (int j=1; j<=2; j++)
    if (board_rep[j][2-j] != winpiece)
      twin=false;
  if (twin && (winpiece != no_piece))
    return piece_to_player(winpiece);
  twin=true;
  for (int i=0; i<=2; i++)
    for (int j=0; j<=2; j++)
      if (board_rep[i][j] == no_piece)
	twin=false;
  if (twin)
    return -2;
  else return -1;
}

void tic_board::associate(game *g) {
  board::associate(g);
  check(g->players() == 2,"tic_board::associate: Yaah! I can't associate that number of players!");
  g->get_player(0)->set_position("X");   // Player 0 is X
  g->get_player(1)->set_position("O");   // Player 1 is O
}

typeinfo_t tic_board::typeinfo = new_typeinfo();

tic_board::~tic_board() {}
@


1.4
log
@Integrate oral presentation changes into main line.
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3.2.5 1995/12/01 02:33:22 jered Exp $
d28 3
a30 3
    check((0 < xpos) && (xpos <=2), "tic_move: Invalid xpos!");
    check((0 < ypos) && (ypos <=2), "tic_move: Invalid ypos!");
    check((cpiece == tic_board::x_piece) && (cpiece == tic_board::o_piece), 
@


1.3
log
@Did enough that tic_board should work now.
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.2 1995/11/28 03:01:48 jered Exp $
d6 1
d47 1
a47 1
  virtual void display(extensions *ext, ostream& body) {
d138 1
a138 1
  tic_move::tic_piece ppiece;     // Tplayer's piece type
d160 2
a161 1
  if (player_to_piece(p) != ptr->get_piece()) then return false;
d180 6
a185 4
bool tic_board::unapply(move &m, int p) {
  won_player = -1;  
  turn_token=1-turn_token;
  board_rep[ptr->get_xpos()].store(ptr->get_ypos(),no_piece);  
d198 2
a199 2
  for (i=0; i <= 2; i++) {
    for (j=0; j <= 2; j++)
d208 4
a211 3
  move_generator* mg = new tic_move_gen(p, this); 
  bool retval=mg->get();
  dispose mg;
d216 1
a216 1
  return new tic_move_gen(p, this); }
d240 12
d258 1
a258 1
  swtich (cpiece) {
d267 2
a268 1
  }
d271 1
a271 1
tic_piece tic_board::player_to_piece(int p) {
d331 1
a331 2
  check(g->players() == 2,"tic_board::associate: Yaah! I can't associate that"
	"number of players!");
d337 2
@


1.3.2.1
log
@Make it compile if not link
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3 1995/11/30 07:16:25 jered Exp $
a5 1
#include <player.h>
d46 1
a46 1
    virtual void display(extensions *, ostream& body) {
d137 1
a137 1
    tic_board::tic_piece ppiece;     // Tplayer's piece type
d159 1
a159 2
  if (player_to_piece(p) != ptr->get_piece())
       return false;
d178 4
a181 6
bool tic_board::unapply(move &m, int ) {
    tic_move* ptr = (tic_move*)m.force(tic_move::typeinfo);
    if (!ptr) return false;
    won_player = -1;  
    turn_token=1-turn_token;
    board_rep[ptr->get_xpos()].store(ptr->get_ypos(),no_piece);  
d194 2
a195 2
  for (int i=0; i <= 2; i++) {
      for (int j=0; j <= 2; j++)
d204 3
a206 4
  move_generator* mg = new tic_move_gen(p, (tic_board *) this); 
move *foo;
  bool retval=mg->get(foo);
  delete mg;
d211 1
a211 1
  return new tic_move_gen(p, (tic_board *) this); }
d241 1
a241 1
  switch (cpiece) {
d250 1
a250 2
  };
  abort();
d253 1
a253 1
tic_board::tic_piece tic_board::player_to_piece(int p) {
@


1.3.2.2
log
@Fixed clone, clone_part on tic_board.
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3.2.1 1995/11/30 08:35:27 hartmans Exp $
a237 12
}

board* tic_board::clone() const {
  tic_board *tb = new tic_board();
  board::clone_part(*tb);
  clone_part(*tb);
}

void tic_board::clone_part(board &b) const {
  b.won_player = won_player;
  b.turn_token = turn_token;
  b.board_rep = board_rep;
@


1.3.2.3
log
@Fix typo
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3.2.2 1995/11/30 08:49:54 jered Exp $
d246 1
a246 1
void tic_board::clone_part(tic_board &b) const {
@


1.3.2.4
log
@change stuff
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3.2.3 1995/11/30 09:25:32 hartmans Exp $
a337 2

tic_board::~tic_board() {}
@


1.3.2.5
log
@Changed string quoting thing.
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.3.2.4 1995/11/30 10:03:15 hartmans Exp $
d331 2
a332 1
  check(g->players() == 2,"tic_board::associate: Yaah! I can't associate that number of players!");
@


1.2
log
@tic_board changes I made on the airplane. More implementation
on check_if_won, I think.
@
text
@d1 1
a1 1
// $Id: tic_board.C,v 1.1 1995/11/26 04:20:25 jered Exp $
d29 1
a29 1
    check((cpiece == tic_board::x_piece) && (cpiece == tic_board::y_piece), 
d56 3
a58 2
    if (!ptr) return false;                    // They're not even the same type...
    return ((tpiece == ptr->tpiece) && (txpos == ptr->txpos) && (typos == ptr->typos));
d62 2
a63 2
  // Overview: Dups a tic_move. This allows the copy method to work in the virtual
  // class move.
d96 2
a97 2
// FIXME It's rather unclear that this is valid, is run, or even does what we want. --J
typeinfo_t tic_move::typeinfo = new_typeinfo();   // Initializes tic_move's typeinfo
d101 5
a105 6
// FIXME Should this really generate move *? Or tic_move *? (It could make a difference.)
class tic_move_gen : public generator <move *> {
// Overview: This creates 1 6.170 generator that iterates over all valid moves for a given
// player and board. Neither the board nor player may change while the iterator is in
// use. The player's position, and the piece corresponding to that position may not change,
// as well.
d108 1
a108 2
  tic_move_gen(player *p, tic_board *cboard) {
  // Checks: Player p must have a position. 
d110 1
a110 3
  // Effects: constructs a generator that returns the valid moves
  // given curr_highest as the current highest piece taken.
    string ppos;     // tplayer's position
d113 1
a113 3
    check(tplayer->get_position(ppos),"tic_move_gen::tic_move_gen; Player doesn't 
          have position!");
    ppiece = tic_board::pos_to_piece(ppos);
d116 1
a116 1
  bool get(move *&m) {
d136 1
a136 1
  player *tplayer;                // The player we are generating moves for
a142 1
// FIXME Does this really do the right thing on the stack?
d150 2
a151 2
  won_player = NULL;
  turn_token = 'X';                       // X goes first
d154 1
a154 1
bool tic_board::is_legal_move(move &m, const player *p) const {
d156 1
a156 1
  if (won_player) return false;  // The game is over
d159 2
a160 4
  check(p->get_position(string ppos),"tic_board::is_legal_move; Player doesn't 
          have position!");      // Can p place this piece?
  if (pos_to_piece(ppos) != ptr->get_piece()) then return false;
  if (ppos[0] != turn_token) return false;  // It's not p's turn 
d166 1
a166 1
game::move_result tic_board::apply(move &m, player *p) {
d172 3
a174 5
  if (!won_player)                     // Check and see if p just won
    won_player = this.check_for_winner();
  if (turn_token == 'X')
    turn_token = 'O';
    else turn_token = 'X';
d178 3
a180 5
bool tic_board::unapply(move &m, const player *p) {
  won_player = NULL;  
  if (turn_token == 'X')
    turn_token = 'O';
    else turn_token = 'X';
d184 1
a184 1
player* tic_board::winner() {
d192 1
a192 1
void tic_board::display(extensions *ext, ostream& body) const {
d201 1
a201 1
bool tic_board::valid_move_available(const player *p) const {
d204 1
a204 1
  generator<move*>* mg = new tic_move_gen(p, *this); 
d210 2
a211 2
generator<move*>* tic_board::valid_moves(const player *p) const{
  return new tic_move_gen(p, *this); }
d213 1
a213 1
board::value tic_board::eval_move_delta(move &m, const player *p) const {
d223 1
d226 1
a226 1
board::value tic_board::evaluate(const player *p) const {
d232 1
d253 3
a255 3
tic_piece tic_board::pos_to_piece(string &ppos) {
  if (ppos == "X") return x_piece;
  if (ppos == "O") return o_piece;
d259 9
a267 3
player* tic_board::check_for_winner() {
// Effects: Returns the winner of this if a player has won, NULL if nobody has won,
// something else if there is a draw.  The return value is undefined if more than
d276 41
a316 2
      {Uhh...what goes here?};
  
@


1.1
log
@Implementation and interface changes, see ChangLog.
(Attempting to commit again.)
#$@@$@@ Linux-AFS over SLIP.
@
text
@d1 1
a1 1
// $Id$
d95 1
a95 1
// FIXME It's rather unclear that this is valid, is run, or even does what we wants. --J
d103 1
a103 1
// player and board. Neither the board nor player may change while the interator is in
d125 1
d128 6
d135 1
a135 1
    if (tx > 2) { tx = 0; ty++; }
d157 1
a159 2
//FIXME Are there legal moves after a game has been won?
//FIXME This should also see if it's p's turn, shouldn't it?
d162 1
d167 2
a168 1
  if (pos_to_piece(ppos) != ptr->get_piece()) then return false; 
a173 1
//FIXME This should probably advance to the next player's turn.
d182 3
a187 1
//FIXME This should probably backup to the last player's turn.
d190 3
d206 2
a207 2
  for (i=0; i < 2; i++) {
    for (j=0; j < 2; j++)
d270 12
a281 1
//FIXME write me
@
