-
Notifications
You must be signed in to change notification settings - Fork 163
/
Copy pathTicTacToe.cs
239 lines (203 loc) · 6.58 KB
/
TicTacToe.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#define CSHARP2PLUS
namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.TicTacToe;
using System;
#pragma warning disable 1030 // Disable user-defined warnings
// The TicTacToe class enables two players to
// play tic-tac-toe.
public class TicTacToeGame // Declares the TicTacToeGame class.
{
static public void Main() // Declares the entry point to the program.
{
// Stores locations each player has moved.
int[] playerPositions = { 0, 0 };
// Initially set the currentPlayer to Player 1.
int currentPlayer = 1;
// Winning player
int winner = 0;
string input = "Let the game begin!";
// Display the board and
// prompt the current player
// for his next move.
for(int turn = 1; turn <= 10; ++turn)
{
DisplayBoard(playerPositions);
#region Check for End Game
if(EndGame(winner, turn, input))
{
break;
}
#endregion Check for End Game
input = NextMove(playerPositions, currentPlayer);
winner = DetermineWinner(playerPositions);
// Switch players.
currentPlayer = (currentPlayer == 2) ? 1 : 2;
}
}
private static string NextMove(int[] playerPositions,
int currentPlayer)
{
string? input;
// Repeatedly prompt the player for a move
// until a valid move is entered.
bool validMove;
do
{
// Request a move from the current player.
System.Console.Write($"\nPlayer {currentPlayer} - Enter move:");
// TODO: Update listing in Manuscript
input = System.Console.ReadLine();
validMove = ValidateAndMove(playerPositions,
currentPlayer, input);
} while(!validMove);
return input!;
}
static bool EndGame(int winner, int turn, string input)
{
bool endGame = false;
if(winner > 0)
{
System.Console.WriteLine($"\nPlayer {winner} has won!!!!");
endGame = true;
}
else if(turn == 10)
{
// After completing the 10th display of the
// board, exit rather than prompting the
// user again.
System.Console.WriteLine("\nThe game was a tie!");
endGame = true;
}
else if(input.Length == 0 || input == "quit")
{
// Check if user quit by hitting Enter without
// any characters or by typing "quit".
System.Console.WriteLine("The last player quit");
endGame = true;
}
return endGame;
}
static int DetermineWinner(int[] playerPositions)
{
int winner = 0;
// Determine if there is a winner.
int[] winningMasks = {
7, 56, 448, 73, 146, 292, 84, 273};
foreach(int mask in winningMasks)
{
if((mask & playerPositions[0]) == mask)
{
winner = 1;
break;
}
else if((mask & playerPositions[1]) == mask)
{
winner = 2;
break;
}
}
return winner;
}
static bool ValidateAndMove(
int[] playerPositions, int currentPlayer, string? input)
{
bool valid = false;
// Check the current player’s input.
switch(input)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
#warning "Same move allowed multiple times."
int shifter; // The number of places to shift
// over to set a bit.
int position; // The bit which is to be set.
// int.Parse() converts "input" to an integer.
// "int.Parse(input) – 1" because arrays
// are zero-based.
shifter = int.Parse(input) - 1;
// Shift mask of 00000000000000000000000000000001
// over by cellLocations.
position = 1 << shifter;
// Take the current player cells and OR them
// to set the new position as well.
// Since currentPlayer is either 1 or 2 you
// subtract 1 to use currentPlayer as an
// index in a zero-based array.
playerPositions[currentPlayer - 1] |= position;
valid = true;
break;
case null:
case "quit":
valid = true;
break;
case "":
default:
// If none of the other case statements
// is encountered, then the text is invalid.
System.Console.WriteLine(
"\nERROR: Enter a value from 1-9. "
+ "Push ENTER to quit");
break;
}
return valid;
}
static void DisplayBoard(int[] playerPositions)
{
// This represents the borders between each cell
// for one row.
string[] borders = {
"|", "|", "\n---+---+---\n", "|", "|",
"\n---+---+---\n", "|", "|", ""
};
// Display the current board;
int border = 0; // set the first border (border[0] = "|").
#if CSHARP2PLUS
System.Console.Clear();
#endif
for(int position = 1;
position <= 256;
position <<= 1, border++)
{
char token = CalculateToken(
playerPositions, position);
// Write out a cell value and the border that
// comes after it.
System.Console.Write($" {token} {borders[border]}");
}
}
static char CalculateToken(
int[] playerPositions, int position)
{
// Initialize the players to 'X' and 'O'
char[] players = { 'X', 'O' };
char token;
// If player has the position set,
// then set the token to that player.
if((position & playerPositions[0]) == position)
{
// Player 1 has that position marked.
token = players[0];
}
else if((position & playerPositions[1]) == position)
{
// Player 2 has that position marked.
token = players[1];
}
else
{
// The position is empty.
token = ' ';
}
return token;
}
#line 113 "TicTacToe.cs"
// Generated code goes here.
#line default
}