Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) TicTacToe

 

TicTacToe is a class embodying the game logic of Tic-Tac-Toe.

 

TicTacToe is used by, among others:

 

 

 

 

 

tictactoe.h

 

//---------------------------------------------------------------------------
/*
TicTacToe, tic-tac-toe game class
Copyright (C) 2010 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppTicTacToe.htm
//---------------------------------------------------------------------------
#ifndef TICTACTOE_H
#define TICTACTOE_H
//---------------------------------------------------------------------------
#include <iosfwd>
#include <boost/multi_array.hpp>
//---------------------------------------------------------------------------
///TicTacToe is a tic-tac-toe game class.
struct TicTacToe
{
  enum { empty     = 0 };
  enum { player1   = 1 };
  enum { player2   = 2 };
  enum { draw      = 3 };
  enum { no_winner = 4 };

  ///TicTacToe default contructor creates an empty board,
  ///where the current turn is to player1.
  TicTacToe();

  ///TicTacToe contructor from summized state integer.
  TicTacToe(const int state);

  ///CanDoMove returns if a move at a certain position is valid.
  bool CanDoMove(const int x, const int y) const;

  ///DoMove lets m_current_player put his token at a certain
  ///position on the board.
  void DoMove(const int x, const int y);

  ///GetBoard returns the tic-tac-toe board.
  const boost::multi_array<int,2>& GetBoard() const { return m_board; }

  ///GetCurrentPlayer returns whose turn it is.
  int GetCurrentPlayer() const { return m_current_player; }

  ///GetCurrentTurn returns the turn number.
  int GetCurrentTurn() const;

  ///GetSquare returns the content at square (x,y)
  int GetSquare(const int x,const int y) const;

  ///GetSummarizedState returns an integer summarizing the
  ///state, which is both tic-tac-toe board and whose turn it is.
  int GetSummarizedState() const;

  ///GetVersion returns the TicTacToe version
  static const std::string GetVersion() { return "1.3.1"; }

  ///GetWinner returns the winner.
  ///* TicTacToe::player1   : player1 has won.
  ///* TicTacToe::player2   : player2 has won.
  ///* TicTacToe::draw      : draw.
  ///* TicTacToe::no_winner : no winner.
  ///The constant TicTacToe::empty should _not_ be returned.
  int GetWinner() const;

  ///SetBoard sets a tic-tac-toe board.
  void SetBoard(const boost::multi_array<int,2>& board);

  ///SetSquare sets the value of square (x,y).
  void SetSquare(const int x, const int y, const int square_state);

  ///SetSummarizedState sets the TicTacToe state,
  ///which is both tic-tac-toe board and whose turn it is.
  void SetSummarizedState(int state);

  private:

  ///m_board stores the board in an x-y-order.\n
  ///TicTacToe::empty : empty\n
  ///TicTacToe::player1 : occupied by player 1\n
  ///TicTacToe::player2 : occupied by player 2\n
  boost::multi_array<int,2> m_board;
  int m_current_player;

  ///NoEmptySquares determines whether there are no empty squares left.
  bool NoEmptySquares() const;

  friend std::ostream& operator<<(std::ostream& os,const TicTacToe& t);
};
//---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os,const TicTacToe& t);
//---------------------------------------------------------------------------
bool operator==(const TicTacToe& lhs, const TicTacToe& rhs);
//---------------------------------------------------------------------------
///From http://www.richelbilderbeek.nl/CppIntPower.htm
int IntPower(const int base, const int exponent);
//---------------------------------------------------------------------------
//YYYY-MM-DD: version X.Y: [description]
//2010-09-19: version 1.3: made CanDoMove method a const method

#endif // TICTACTOE_H

 

 

 

 

 

tictactoe.cpp

 

//---------------------------------------------------------------------------
/*
TicTacToe, tic-tac-toe game class
Copyright (C) 2010 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppTicTacToe.htm
//---------------------------------------------------------------------------
#include <algorithm>
#include <iostream>
#include <stdexcept>
//---------------------------------------------------------------------------
#include "tictactoe.h"
//---------------------------------------------------------------------------
///TicTacToe default contructor creates an empty board,
///where the current turn is to player1.
TicTacToe::TicTacToe()
  : m_board(boost::extents[3][3]),
    m_current_player(TicTacToe::player1)
{
  for (int i=0; i!=9; ++i)
  {
    m_board[i/3][i%3] = TicTacToe::empty;
  }

  assert(GetCurrentTurn() == 0);
  assert(GetCurrentPlayer() == TicTacToe::player1);
}
//---------------------------------------------------------------------------
///TicTacToe contructor from summized state integer.
TicTacToe::TicTacToe(const int state)
  : m_board(boost::extents[3][3]),
    m_current_player(-1)
{
  SetSummarizedState(state);

  assert(GetCurrentPlayer() == TicTacToe::player1
    ||   GetCurrentPlayer() == TicTacToe::player2);
}
//---------------------------------------------------------------------------
bool TicTacToe::CanDoMove(const int x, const int y) const
{
  if (m_board[x][y]==0) return true;
  return false;
}
//---------------------------------------------------------------------------
void TicTacToe::DoMove(const int x, const int y)
{
  assert(CanDoMove(x,y));
  //std::clog << "Player " << m_current_player
  //  << ": (" << x << "," << y << ")\n";
  m_board[x][y] = m_current_player;
  m_current_player = (m_current_player == 1 ? 2 : 1);
}
//---------------------------------------------------------------------------
///GetCurrentTurn returns the turn number.
int TicTacToe::GetCurrentTurn() const
{
  int turn = 0;
  for (int i=0; i!=9; ++i)
  {
    if (m_board[i/3][i%3] != TicTacToe::empty) ++turn;
  }
  return turn;
}
//---------------------------------------------------------------------------
///GetSquare returns the content at square (x,y)
int TicTacToe::GetSquare(const int x,const int y) const
{
  return m_board[x][y];
}
//---------------------------------------------------------------------------
///GetSummarizedState returns an integer summarizing the
///state, which is both tic-tac-toe board and whose turn it is.
///In trinary, for lowest order digit:\n
///# : content\n
///0 : content of (0,0)\n
///1 : content of (1,0)\n
///2 : content of (2,0)\n
///3 : content of (0,1)\n
///4 : content of (1,1)\n
///5 : content of (2,1)\n
///6 : content of (0,2)\n
///7 : content of (1,2)\n
///8 : content of (2,2)\n
///9 : current turn\n
///For indices [0,8] content is stored as:
///[#] : description\n
/// 0  : empty\n
/// 1  : player1\n
/// 2  : player2\n
///For index 9 content is stored as:
///[#] : description\n
/// 0  : ERROR\n
/// 1  : player1\n
/// 2  : player2\n
int TicTacToe::GetSummarizedState() const
{
  int z = m_board[0][0];
  for (int i=1; i!=9; ++i)
  {
    z += (m_board[i/3][i%3] * IntPower(3,i));
  }
  z += (m_current_player * IntPower(3,9));
  return z;
}
//---------------------------------------------------------------------------
///GetWinner returns the winner.
///TicTacToe::no_winner : no winner yet\n
///TicTacToe::player1   : player1 has won\n
///TicTacToe::player2   : player2 has won\n
///TicTacToe::draw      : draw\n
int TicTacToe::GetWinner() const
{
  //Check rows
  for (int y=0; y!=3; ++y)
  {
    if (m_board[0][y] != TicTacToe::empty
     && m_board[0][y] == m_board[1][y]
     && m_board[1][y] == m_board[2][y])
      return m_board[0][y];
  }
  //Check collumns
  for (int x=0; x!=3; ++x)
  {
    if (m_board[x][0] != TicTacToe::empty
     && m_board[x][0] == m_board[x][1]
     && m_board[x][1] == m_board[x][2])
       return m_board[x][0];
  }
  //Check diagonal
  if (m_board[0][0] != TicTacToe::empty
   && m_board[0][0] == m_board[1][1]
   && m_board[1][1] == m_board[2][2])
    return m_board[1][1];
  //Check other diagonal
  if (m_board[0][2] != TicTacToe::empty
   && m_board[0][2] == m_board[1][1]
   && m_board[1][1] == m_board[2][0])
    return m_board[1][1];
  //Check for draw
  if (NoEmptySquares())return TicTacToe::draw;
  //No winner
  return TicTacToe::no_winner;
}
//---------------------------------------------------------------------------
bool TicTacToe::NoEmptySquares() const
{
  for (int i=0; i!=9; ++i)
  {
    if (m_board[i/3][i%3] == TicTacToe::empty) return false;
  }
  return true;
}
//---------------------------------------------------------------------------
///SetBoard sets a tic-tac-toe board.
void TicTacToe::SetBoard(const boost::multi_array<int,2>& board)
{
  m_board = board;

  #ifndef NDEBUG
  {
    for (int i=0; i!=9; ++i)
    {
      const int z = m_board[i/3][i%3];
      assert(z == TicTacToe::empty
          || z == TicTacToe::player1
          || z == TicTacToe::player2);
    }
  }
  #endif
}
//---------------------------------------------------------------------------
///SetSquare sets the value of square (x,y).
void TicTacToe::SetSquare(
  const int x, const int y, const int square_state)
{
  assert(square_state == TicTacToe::empty
    || square_state == TicTacToe::player1
    || square_state == TicTacToe::player2);

  m_board[x][y] = square_state;

  //Internal test
  assert(GetSquare(x,y)==square_state);
}
//---------------------------------------------------------------------------
///SetSummarizedState sets the TicTacToe state,
///which is both tic-tac-toe board and whose turn it is.
void TicTacToe::SetSummarizedState(const int original_state)
{
  int s = original_state;
  for (int i=0; i!=9; ++i)
  {
    m_board[i/3][i%3] = s % 3;
    s/=3;
  }
  if (s!=TicTacToe::player1 && s != TicTacToe::player2)
  {
    throw std::invalid_argument("Invalid TicTacToe state");
  }

  m_current_player = s;

  //Internal check
  assert(GetSummarizedState()==original_state);
}
//---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os,const TicTacToe& t)
{
  os
    << t.GetSquare(0,0)
    << t.GetSquare(1,0)
    << t.GetSquare(2,0)
    << '\n'
    << t.GetSquare(0,1)
    << t.GetSquare(1,1)
    << t.GetSquare(2,1)
    << '\n'
    << t.GetSquare(0,2)
    << t.GetSquare(1,2)
    << t.GetSquare(2,2);
  return os;
}
//---------------------------------------------------------------------------
bool operator==(const TicTacToe& lhs, const TicTacToe& rhs)
{
  return lhs.GetBoard() == rhs.GetBoard()
      && lhs.GetCurrentPlayer() == rhs.GetCurrentPlayer()
      && lhs.GetCurrentTurn() == rhs.GetCurrentTurn();
}
//---------------------------------------------------------------------------
///From http://www.richelbilderbeek.nl/CppIntPower.htm
int IntPower(const int base, const int exponent)
{
  assert(exponent != 0
    && "When calculating IntPower(x,0) the result "
       "might be zero or one, depending on the context");
  assert(exponent > 0);

  int result = base;
  for (int i=1; i!=exponent; ++i)
  {
    result*=base;
  }
  return result;
}
//---------------------------------------------------------------------------

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml