WHAT'S NEW?
Loading...

Noughts and crosses (Tic tac toe) - C#

In this post I am going to show you how to develop over C# a great game: "Noughts and Crosses". Probably you already know how to play this game but if not, you can check it the wiki directly (I am not going to do it men! is an easy game). My application is console and can play alone, showing the result of the game in the screen after all the movements have been done.


The architecture of the program is divided in 5 different classes:
  1. Program.cs: just runs the start() method of the Play.cs class.
  2. Play.cs: it handles the maximun number of movements, the players (O & X), the currentPlayer and the BoardGame.cs class.
  3. Movement.cs: is like a model class, this class has 3 properties: two are for xy coordinates and one for the player who made the movement.
  4. Player.cs: it has two properties for the Id and a boolean if it wins. It also has a method to make a movement because this application plays alone and it generates a random movement.
  5. BoardGame.cs: it saves in a List class all the movements done by the players and the different positions that we can fill. Also it has several methods to check if there is any winner, to know which user filled what position and to know if a movement is possible or not.
Bellow I show you the different code parts for the classes explained before:
  • Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noughts_and_Crosses
{
    class Program
    {
        /// <summary>
        /// Main method to start the execution
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Play play = new Play();
            play.start();
        }
    }
}
  • Play.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noughts_and_Crosses
{
    class Play
    {
        //Constants
        public const int _maxNumMovements = BoardGame._boardGameSize * BoardGame._boardGameSize;

        //Properties
        public Player PlayerO { get; set; }
        public Player PlayerX { get; set; }
        public Player CurrentPlayer { get; set; }
        public BoardGame BoardGame { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public Play()
        {
            PlayerO = new Player("O");
            PlayerX = new Player("X");
            BoardGame = new BoardGame();
            CurrentPlayer = PlayerO; //By default Player "O" starts always
        }

        /// <summary>
        /// Handles the order of execution.
        /// </summary>
        public void start()
        {
            int movements = 0;
            bool winner = false;
            while (!winner && movements < _maxNumMovements)
            {
                //Who moves now
                BoardGame.requestMovement(CurrentPlayer);

                //Somebody won the match
                winner = BoardGame.anyWinner();

                //next one moves
                changePlayer();

                movements++;
            }

            //End of the execution and printing results
            printResults();
        }

        private void changePlayer()
        {
            if (CurrentPlayer.Id == "O") CurrentPlayer = PlayerX;
            else CurrentPlayer = PlayerO;
        }

        /// <summary>
        /// Here the system shows in the main output the results of the game .
        /// </summary>
        private void printResults()
        {
            string winner;
            if (PlayerX.Winner) winner = PlayerX.Id;
            else if (PlayerO.Winner) winner = PlayerO.Id;
            else winner = "Draw";

            if (winner == "Draw") Console.WriteLine("No winners this time...");
            else Console.WriteLine("Congratulations player " + winner + ", YOU ARE THE WINNER!!!\n");

            Console.WriteLine("These are all the movements made:");
            foreach (Movement move in BoardGame.Movements)
            {
                Console.WriteLine("\t Player: " + move.Player.Id.ToString() + "\t X=" + (move.Xcoord + 1).ToString() + " Y=" + (move.Ycoord + 1).ToString());
            }
            Console.WriteLine("\n\nThanks for playing. Bye!");
            Console.ReadLine();
        }
    }
}
  • Movement.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noughts_and_Crosses
{
    /// <summary>
    /// This class saves the basic structure for a player movement.
    /// </summary>
    class Movement
    {
        //Properties
        public int Xcoord { get; set; }
        public int Ycoord { get; set; }
        public Player Player { get; set; }
    }
}
  • Player.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noughts_and_Crosses
{
    class Player
    {
        //Properties
        public string Id { get; set; }
        public bool Winner { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="userName"></param>
        public Player(string userName)
        {
            Id = userName;
            Winner = false;
        }

        /// <summary>
        /// The player makes a random movement
        /// </summary>
        /// <returns></returns>
        public Movement makeMovement()
        {
            int x, y;
            Random r = new Random();
            Movement move = new Movement();

            x = r.Next(BoardGame._boardGameSize);
            y = r.Next(BoardGame._boardGameSize);
            move.Xcoord = x;
            move.Ycoord = y;
            move.Player = this;
            return move;
        }
    }
}
  • BoardGame.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noughts_and_Crosses
{
    class BoardGame
    {
        //Constants
        public const int _boardGameSize = 3;

        public Player[,] BoardGameTable { get; set; }
        public List<Movement> Movements { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public BoardGame()
        {
            BoardGameTable = new Player[_boardGameSize, _boardGameSize];
            Movements = new List<Movement>();
        }

        /// <summary>
        /// This method checks if somebody won the match
        /// </summary>
        /// <returns></returns>
        public bool anyWinner()
        {
            //In a 3x3 board the min. movements to win is 5
            if (Movements.Count < 5) return false;

            //Rows
            if (isFilled(BoardGameTable[0, 0]) == isFilled(BoardGameTable[0, 1]) && isFilled(BoardGameTable[0, 1]) == isFilled(BoardGameTable[0, 2]))
                return (BoardGameTable[0, 0] == null ? false : BoardGameTable[0, 0].Winner = true);
            if (isFilled(BoardGameTable[1, 0]) == isFilled(BoardGameTable[1, 1]) && isFilled(BoardGameTable[1, 1]) == isFilled(BoardGameTable[1, 2]))
                return (BoardGameTable[1, 0] == null ? false : BoardGameTable[1, 0].Winner = true);
            if (isFilled(BoardGameTable[2, 0]) == isFilled(BoardGameTable[2, 1]) && isFilled(BoardGameTable[2, 1]) == isFilled(BoardGameTable[2, 2]))
                return (BoardGameTable[2, 0] == null ? false : BoardGameTable[2, 0].Winner = true);

            //Columns
            if (isFilled(BoardGameTable[0, 0]) == isFilled(BoardGameTable[1, 0]) && isFilled(BoardGameTable[1, 0]) == isFilled(BoardGameTable[2, 0]))
                return (BoardGameTable[0, 0] == null ? false : BoardGameTable[0, 0].Winner = true);
            if (isFilled(BoardGameTable[0, 1]) == isFilled(BoardGameTable[1, 1]) && isFilled(BoardGameTable[1, 1]) == isFilled(BoardGameTable[2, 1]))
                return (BoardGameTable[0, 1] == null ? false : BoardGameTable[0, 1].Winner = true);
            if (isFilled(BoardGameTable[0, 2]) == isFilled(BoardGameTable[1, 2]) && isFilled(BoardGameTable[1, 2]) == isFilled(BoardGameTable[2, 2]))
                return (BoardGameTable[0, 2] == null ? false : BoardGameTable[0, 2].Winner = true);

            //Diagonals
            if (isFilled(BoardGameTable[0, 0]) == isFilled(BoardGameTable[1, 1]) && isFilled(BoardGameTable[1, 1]) == isFilled(BoardGameTable[2, 2]))
                return (BoardGameTable[0, 0] == null ? false : BoardGameTable[0, 0].Winner = true);
            if (isFilled(BoardGameTable[2, 0]) == isFilled(BoardGameTable[1, 1]) && isFilled(BoardGameTable[1, 1]) == isFilled(BoardGameTable[0, 2])) 
                return (BoardGameTable[2, 0] == null ? false : BoardGameTable[2, 0].Winner = true);

            return false;
        }

        /// <summary>
        /// This method avoids null exceptions validating the object inside the array.
        /// Returns the name of the player for the current coordinates.
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        public string isFilled(Player player)
        {
            if (player == null) return "-";
            else return player.Id.ToString();
        }

        /// <summary>
        /// The player should make a movement now
        /// </summary>
        /// <param name="player"></param>
        public void requestMovement(Player player)
        {
            while (!isValidMovement(player.makeMovement(), player));
        }

        /// <summary>
        /// This method will check if the position in the board is free.
        /// </summary>
        /// <param name="move"></param>
        /// <param name="player"></param>
        /// <returns></returns>
        public bool isValidMovement(Movement move, Player player)
        {
            if (Movements.Count > 0)
                if (Movements.Exists(x => (x.Xcoord == move.Xcoord) && (x.Ycoord == move.Ycoord))) return false;
            BoardGameTable[move.Xcoord, move.Ycoord] = player;
            Movements.Add(move);
            return true;
        }
    }
}
I hope you enjoy with this application. Please, do not hesitate to comment for doubts, errors, mistakes, issues, improvements...

0 comments:

Post a Comment