RosettaCodeData/Task/Tic-tac-toe/C-sharp/tic-tac-toe.cs
Ingy döt Net 68f8f3e56b all tasks
2013-04-11 01:07:29 -07:00

246 lines
7.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RosettaTicTacToe
{
class Program
{
/*================================================================
*Pieces (players and board)
*================================================================*/
static string[][] Players = new string[][] {
new string[] { "COMPUTER", "X" }, // computer player
new string[] { "HUMAN", "O" } // human player
};
const int Unplayed = -1;
const int Computer = 0;
const int Human = 1;
// GameBoard holds index into Players[] (0 or 1) or Unplayed (-1) if location not yet taken
static int[] GameBoard = new int[9];
static int[] corners = new int[] { 0, 2, 6, 8 };
static int[][] wins = new int[][] {
new int[] { 0, 1, 2 }, new int[] { 3, 4, 5 }, new int[] { 6, 7, 8 },
new int[] { 0, 3, 6 }, new int[] { 1, 4, 7 }, new int[] { 2, 5, 8 },
new int[] { 0, 4, 8 }, new int[] { 2, 4, 6 } };
/*================================================================
*Main Game Loop (this is what runs/controls the game)
*================================================================*/
static void Main(string[] args)
{
while (true)
{
Console.Clear();
Console.WriteLine("Welcome to Rosetta Code Tic-Tac-Toe for C#.");
initializeGameBoard();
displayGameBoard();
int currentPlayer = rnd.Next(0, 2); // current player represented by Players[] index of 0 or 1
Console.WriteLine("The first move goes to {0} who is playing {1}s.\n", playerName(currentPlayer), playerToken(currentPlayer));
while (true)
{
int thisMove = getMoveFor(currentPlayer);
if (thisMove == Unplayed)
{
Console.WriteLine("{0}, you've quit the game ... am I that good?", playerName(currentPlayer));
break;
}
playMove(thisMove, currentPlayer);
displayGameBoard();
if (isGameWon())
{
Console.WriteLine("{0} has won the game!", playerName(currentPlayer));
break;
}
else if (isGameTied())
{
Console.WriteLine("Cat game ... we have a tie.");
break;
}
currentPlayer = getNextPlayer(currentPlayer);
}
if (!playAgain())
return;
}
}
/*================================================================
*Move Logic
*================================================================*/
static int getMoveFor(int player)
{
if (player == Human)
return getManualMove(player);
else
{
//int selectedMove = getManualMove(player);
//int selectedMove = getRandomMove(player);
int selectedMove = getSemiRandomMove(player);
//int selectedMove = getBestMove(player);
Console.WriteLine("{0} selects position {1}.", playerName(player), selectedMove + 1);
return selectedMove;
}
}
static int getManualMove(int player)
{
while (true)
{
Console.Write("{0}, enter you move (number): ", playerName(player));
ConsoleKeyInfo keyInfo = Console.ReadKey();
Console.WriteLine(); // keep the display pretty
if (keyInfo.Key == ConsoleKey.Escape)
return Unplayed;
if (keyInfo.Key >= ConsoleKey.D1 && keyInfo.Key <= ConsoleKey.D9)
{
int move = keyInfo.KeyChar - '1'; // convert to between 0..8, a GameBoard index position.
if (GameBoard[move] == Unplayed)
return move;
else
Console.WriteLine("Spot {0} is already taken, please select again.", move + 1);
}
else
Console.WriteLine("Illegal move, please select again.\n");
}
}
static int getRandomMove(int player)
{
int movesLeft = GameBoard.Count(position => position == Unplayed);
int x = rnd.Next(0, movesLeft);
for (int i = 0; i < GameBoard.Length; i++) // walk board ...
{
if (GameBoard[i] == Unplayed && x < 0) // until we reach the unplayed move.
return i;
x--;
}
return Unplayed;
}
// plays random if no winning move or needed block.
static int getSemiRandomMove(int player)
{
int posToPlay;
if (checkForWinningMove(player, out posToPlay))
return posToPlay;
if (checkForBlockingMove(player, out posToPlay))
return posToPlay;
return getRandomMove(player);
}
// purposely not implemented (this is the thinking part).
static int getBestMove(int player)
{
return -1;
}
static bool checkForWinningMove(int player, out int posToPlay)
{
posToPlay = Unplayed;
foreach (var line in wins)
if (twoOfThreeMatchPlayer(player, line, out posToPlay))
return true;
return false;
}
static bool checkForBlockingMove(int player, out int posToPlay)
{
posToPlay = Unplayed;
foreach (var line in wins)
if (twoOfThreeMatchPlayer(getNextPlayer(player), line, out posToPlay))
return true;
return false;
}
static bool twoOfThreeMatchPlayer(int player, int[] line, out int posToPlay)
{
int cnt = 0;
posToPlay = int.MinValue;
foreach (int pos in line)
{
if (GameBoard[pos] == player)
cnt++;
else if (GameBoard[pos] == Unplayed)
posToPlay = pos;
}
return cnt == 2 && posToPlay >= 0;
}
static void playMove(int boardPosition, int player)
{
GameBoard[boardPosition] = player;
}
static bool isGameWon()
{
return wins.Any(line => takenBySamePlayer(line[0], line[1], line[2]));
}
static bool takenBySamePlayer(int a, int b, int c)
{
return GameBoard[a] != Unplayed && GameBoard[a] == GameBoard[b] && GameBoard[a] == GameBoard[c];
}
static bool isGameTied()
{
return !GameBoard.Any(spot => spot == Unplayed);
}
/*================================================================
*Misc Methods
*================================================================*/
static Random rnd = new Random();
static void initializeGameBoard()
{
for (int i = 0; i < GameBoard.Length; i++)
GameBoard[i] = Unplayed;
}
static string playerName(int player)
{
return Players[player][0];
}
static string playerToken(int player)
{
return Players[player][1];
}
static int getNextPlayer(int player)
{
return (player + 1) % 2;
}
static void displayGameBoard()
{
Console.WriteLine(" {0} | {1} | {2}", pieceAt(0), pieceAt(1), pieceAt(2));
Console.WriteLine("---|---|---");
Console.WriteLine(" {0} | {1} | {2}", pieceAt(3), pieceAt(4), pieceAt(5));
Console.WriteLine("---|---|---");
Console.WriteLine(" {0} | {1} | {2}", pieceAt(6), pieceAt(7), pieceAt(8));
Console.WriteLine();
}
static string pieceAt(int boardPosition)
{
if (GameBoard[boardPosition] == Unplayed)
return (boardPosition + 1).ToString(); // display 1..9 on board rather than 0..8
return playerToken(GameBoard[boardPosition]);
}
private static bool playAgain()
{
Console.WriteLine("\nDo you want to play again?");
return Console.ReadKey(false).Key == ConsoleKey.Y;
}
}
}