|
ASP Tic Tac Toe
By Steven Smith
This application demonstrates the use of Sessions, state, and database calls to create a
simple tic-tac-toe game. There are no ActiveX components in use on either the client or
the server. The table involved is quite simple, and was created with the following SQL
statement:
CREATE TABLE TicTacToe
(game_id int,
player_name VARCHAR(50),
player_char VARCHAR(1),
turn int DEFAULT 0
PRIMARY KEY (game_id,turn),
location int)
The source code is rather lengthy, as it includes a number of functions for the computer AI
to use to determine where to move next. The complete code is listed below:
1 <% OPTION EXPLICIT %> 2 <!-- #INCLUDE VIRTUAL="/stevesmith/include/articleformat.asp" --> 3 <!-- #INCLUDE VIRTUAL="activeserverpageslib.asp" --> 4 <!-- #INCLUDE VIRTUAL="/stevesmith/script.asp" --> 5 <% 6 Call ArticleHeader("ASP Tic Tac Toe Game","","PRE { color : blue; }") 7 %> 8 <% 9 'Declare Variables 10 Dim Turn 'The current turn 11 Dim PlayerName 'Player's Name 12 Dim Location 'Location 13 Dim GameID 'This Game's Identifier 14 Dim sql 'Variable to hold sql string 15 Dim RS 'Default Recordset Object 16 Dim I 'For Loop Counter 17 Dim Board(9) 'Array holding current locations 18 Dim WinLine(3) 'Array holding winning line 19 Dim Winner 'String holding name of winner 20 Dim WinOrBlockLocation 'Location Index of a winning move 21 Dim PlayerChar 'Player's Character 22 Dim CPUChar 'Computer's Character 23 24 PlayerChar = "X" 25 CPUChar = "O" 26 27 'Define Subs 28 Sub UpdatePlayerTurn 29 If Request("GameID") = "New Game" Then 30 'If First Turn, Request will say "New Game"; set Game ID to MAX(game_id) + 1 31 sql = " SELECT MAX(game_id) AS maxid FROM TicTacToe " 32 'Response.Write sql & "<BR>" 33 Set RS = DBQuery(sql) 34 GameID = RS("maxid") + 1 35 If GameID&"" = "" Then GameID = 1 36 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 37 " VALUES (" & GameID & ",'" & PlayerName & "','X'," & Turn & "," & Location & "); " 38 'Response.Write sql & "<BR>" 39 Set RS = DBQuery(sql) 40 Else 41 GameID = Request("GameID") 42 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 43 " VALUES (" & GameID & ",'" & PlayerName & "','X'," & Turn & "," & Location & "); " 44 'Response.Write sql & "<BR>" 45 Set RS = DBQuery(sql) 46 End If 47 Turn = Turn + 1 48 End Sub 49 50 Function CheckLine(a,b,c) 51 If IsNull(Board(a)) OR IsNull(Board(b)) OR IsNull(Board(c)) Then 52 CheckLine = "None" 53 Exit Function 54 End If 55 If Board(a) = "" OR Board(b) = "" OR Board(c) = "" Then 56 CheckLine = "None" 57 Exit Function 58 End If 59 If Board(a) = Board(b) And Board(b) = Board(c) Then 60 CheckLine = Board(a) 61 WinLine(1) = a 62 WinLine(2) = b 63 WinLine(3) = c 64 Exit Function 65 Else 66 CheckLine = "None" 67 Exit Function 68 End If 69 Response.Write "Should not be here." 70 End Function 71 72 Function Check2of3 (a,b,c,p) 73 'a,b,c are indexes to board locations 74 'p is a character ("X" or "O") 75 If Board(a) = Board(b) And Board(c) = "" And Board(a) = p Then 76 Check2of3 = c 77 Exit Function 78 End If 79 If Board(a) = Board(c) And Board(b) = "" And Board(a) = p Then 80 Check2of3 = b 81 Exit Function 82 End If 83 If Board(b) = Board(c) And Board(a) = "" And Board(b) = p Then 84 Check2of3 = a 85 Exit Function 86 End If 87 Check2of3 = 0 88 End Function 89 90 Function CheckWin 91 Dim Winner 92 Winner = "None" 93 sql = "SELECT * FROM TicTacToe WHERE game_id = " & GameID & " ORDER BY location " 94 'Response.Write sql & "<BR>" 95 Set RS = DBQuery(sql) 96 97 'Fill the Board Array 98 While Not RS.EOF 99 'Response.Write RS("location") & " " & RS("player_char") & "<BR>" 100 I = RS("location") 101 Board(I) = RS("player_char") 102 RS.MoveNext 103 Wend 104 105 'Cannot have a winner before turn 5 106 If Turn < 5 Then 107 CheckWin = Winner 108 Exit Function 109 End If 110 111 'Check all 8 possible win combos 112 Winner = CheckLine(1,2,3) 113 If Winner <> "None" Then 114 CheckWin = Winner 115 Exit Function 116 End If 117 Winner = CheckLine(4,5,6) 118 If Winner <> "None" Then 119 CheckWin = Winner 120 Exit Function 121 End If 122 Winner = CheckLine(7,8,9) 123 If Winner <> "None" Then 124 CheckWin = Winner 125 Exit Function 126 End If 127 Winner = CheckLine(1,5,9) 128 If Winner <> "None" Then 129 CheckWin = Winner 130 Exit Function 131 End If 132 Winner = CheckLine(3,5,7) 133 If Winner <> "None" Then 134 CheckWin = Winner 135 Exit Function 136 End If 137 Winner = CheckLine(1,4,7) 138 If Winner <> "None" Then 139 CheckWin = Winner 140 Exit Function 141 End If 142 Winner = CheckLine(2,5,8) 143 If Winner <> "None" Then 144 CheckWin = Winner 145 Exit Function 146 End If 147 Winner = CheckLine(3,6,9) 148 If Winner <> "None" Then 149 CheckWin = Winner 150 Exit Function 151 End If 152 CheckWin =Winner 153 End Function 154 155 Function CanWinOrBlock(character) 156 'Character is either "X" or "O" 157 WinOrBlockLocation = Check2of3(1,2,3,character) 158 If WinOrBlockLocation > 0 Then 159 CanWinOrBlock = True 160 Exit Function 161 End If 162 WinOrBlockLocation = Check2of3(4,5,6,character) 163 If WinOrBlockLocation > 0 Then 164 CanWinOrBlock = True 165 Exit Function 166 End If 167 WinOrBlockLocation = Check2of3(7,8,9,character) 168 If WinOrBlockLocation > 0 Then 169 CanWinOrBlock = True 170 Exit Function 171 End If 172 WinOrBlockLocation = Check2of3(1,5,9,character) 173 If WinOrBlockLocation > 0 Then 174 CanWinOrBlock = True 175 Exit Function 176 End If 177 WinOrBlockLocation = Check2of3(3,5,7,character) 178 If WinOrBlockLocation > 0 Then 179 CanWinOrBlock = True 180 Exit Function 181 End If 182 WinOrBlockLocation = Check2of3(1,4,7,character) 183 If WinOrBlockLocation > 0 Then 184 CanWinOrBlock = True 185 Exit Function 186 End If 187 WinOrBlockLocation = Check2of3(2,5,8,character) 188 If WinOrBlockLocation > 0 Then 189 CanWinOrBlock = True 190 Exit Function 191 End If 192 WinOrBlockLocation = Check2of3(3,6,9,character) 193 If WinOrBlockLocation > 0 Then 194 CanWinOrBlock = True 195 Exit Function 196 End If 197 CanWinOrBlock = False 198 End Function 199 200 Sub UpdateComputerTurn 201 If CanWinOrBlock(CPUChar) Then 202 Location = WinOrBlockLocation 203 ElseIf CanWinOrBlock(PlayerChar) Then 204 Location = WinOrBlockLocation 205 ElseIf Board(6) = PlayerChar AND Board(8) = PlayerChar AND Board(9) = "" Then 206 Location = 9 207 ElseIf Board(1) = PlayerChar AND Board(9) = PlayerChar AND Board(2) = "" Then 208 Location = 2 209 ElseIf Board(3) = PlayerChar AND Board(7) = PlayerChar AND Board(2) = "" Then 210 Location = 2 211 ElseIf Board(1) = PlayerChar AND Board(8) = PlayerChar AND Board(7) = "" Then 212 Location = 7 213 ElseIf Board(3) = PlayerChar AND Board(8) = PlayerChar AND Board(6) = "" Then 214 Location = 6 215 ElseIf Board(5) = "" Then 216 Location = 5 217 ElseIf Board(1) = "" Then 218 Location = 1 219 ElseIf Board(3) = "" Then 220 Location = 3 221 ElseIf Board(7) = "" Then 222 Location = 7 223 ElseIf Board(9) = "" Then 224 Location = 9 225 ElseIf Board(2) = "" Then 226 Location = 2 227 ElseIf Board(4) = "" Then 228 Location = 4 229 ElseIf Board(6) = "" Then 230 Location = 6 231 ElseIf Board(8) = "" Then 232 Location = 8 233 End If 234 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 235 " VALUES (" & GameID & ",'Computer','O'," & Turn & "," & Location & "); " 236 'Response.Write sql & "<BR>" 237 Set RS = DBQuery(sql) 238 Turn = Turn + 1 239 End Sub 240 241 ' InArray takes a value and an array and returns true if the array contains the value 242 Function InArray(element,array) 243 Dim I 'Local 244 For I = 1 To UBound(array) 245 If array(I) = element Then 246 InArray = True 247 Exit Function 248 End If 249 Next 250 InArray = False 251 End Function 252 253 ' rndcolor returns a random HTML color 254 Function rndcolor() 255 Dim LightDarkRange 256 Dim forered 257 Dim foregreen 258 Dim foreblue 259 Dim color 260 LightDarkRange = 150 261 forered = Int(Rnd * LightDarkRange) 262 foregreen = Int(Rnd * LightDarkRange) 263 foreblue = Int(Rnd * LightDarkRange) 264 color = "#" & cstr(Hex(RGB(forered, foregreen, foreblue))) 265 rndcolor=color 266 End Function 267 268 269 %> 270 <H1>Tic-Tac-Toe</H1> 271 <FORM NAME="Form1" ACTION="tictactoegame.asp" METHOD="POST"> 272 <% 273 If Request("PlayerName") = "" Then 274 %> 275 Enter your name: <INPUT TYPE=TEXT NAME="PlayerName" VALUE="<%=Session("TicTacToePlayer")%>" MAXLENGTH=50 276 onChange='return checkField(this);'> 277 <BR> 278 <INPUT TYPE=SUBMIT VALUE="Submit"> 279 <SCRIPT TYPE="text/javascript"> 280 <!-- 281 function checkField(s){ 282 if (s.value.indexOf("<") > 0 || s.value.indexOf(">") > 0) { 283 alert("You may not use HTML tags."); 284 s.focus(); 285 return false; 286 } 287 return true; 288 } 289 document.Form1.PlayerName.focus(); 290 // --> 291 </SCRIPT> 292 </FORM> 293 <A HREF="http://<%=Request.ServerVariables("SERVER_NAME")%>/stevesmith/articles/tictactoe.asp"> 294 See Source</A> 295 <P> 296 (Game AI last updated 20 August 1999)<BR> 297 (Database Reset 21 Jun 2000) 298 <H2>Score Results:</H2> 299 <% 300 sql = "SELECT Count(game_id) As cnt FROM TicTacToe WHERE location=10" 301 set RS = DBQuery(sql) 302 %> 303 <TABLE BORDER=1> 304 <CAPTION><B><%=RS("cnt")%> Total Games</B></CAPTION> 305 <TR> 306 <TH>Winner</TH> 307 <TH>Total</TH> 308 <TH>Graph</TH> 309 </TR> 310 <% 311 sql = "SELECT player_name,count(player_name) AS cnt FROM TicTacToe WHERE location=10 GROUP BY player_name " 312 set RS = DBQuery(sql) 313 While Not RS.EOF 314 Randomize 315 %> 316 <TR> 317 <TD><%=RS("player_name")%></TD> 318 <TD><%=RS("cnt")%></TD> 319 <TD><table><tr><td width="<%=rs("cnt")%>" height="5" bgcolor="<%= rndcolor() %>" 320 align="bottom"></td></tr></table> 321 </TD> 322 </TR> 323 <% 324 RS.MoveNext 325 Wend 326 %> 327 </TABLE> 328 <% 329 Else 330 Session("TicTacToePlayer") = Request("PlayerName") 331 %> 332 <TABLE WIDTH="100%"> 333 <TR> 334 <TD ALIGN=RIGHT>[<A HREF="tictactoegame.asp">New Game</A>]</TD> 335 </TR> 336 </TABLE> 337 <% 338 ' Perform Player Moves(if not first time) and Computer Moves 339 PlayerName = Request("PlayerName") 340 Location = Request("TTT") 341 If Request("TTT") = "" Then 342 'First time, do nothing 343 Turn = 1 344 GameID = "New Game" 345 Winner = "None" 346 Else 347 Turn = Request("Turn") 348 Call UpdatePlayerTurn 349 Winner = CheckWin 350 If Winner <> "None" Then 351 Response.Write "<H2>Game Over</H2><BR>" 352 Response.Write Winner & " has won the game!<BR>" 353 'Store game result(location = 10) 354 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 355 " VALUES (" & GameID & ",'" & PlayerName & "','X'," & Turn & ",10); " 356 Set RS = DBQuery(sql) 357 End If 358 If Turn < 10 And Winner = "None" Then 359 Call UpdateComputerTurn 360 Winner = CheckWin 361 If Winner <> "None" Then 362 Response.Write "<H2>Game Over</H2><BR>" 363 Response.Write Winner & " has won the game!<BR>" 364 'Store game result(location = 10) 365 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 366 " VALUES (" & GameID & ",'Computer','X'," & Turn & ",10); " 367 Set RS = DBQuery(sql) 368 End If 369 End If 370 If Turn > 9 And Winner = "None" Then 371 Response.Write "<H2>Game Over</H2><BR>" 372 Response.Write "The game ended in a tie.<BR>" 373 'Store game result(location = 10) 374 sql = " INSERT INTO TicTacToe (game_id,player_name,player_char,turn,location) " & _ 375 " VALUES (" & GameID & ",'Tie','X'," & Turn & ",10); " 376 Set RS = DBQuery(sql) 377 End If 378 End If 379 380 381 %> 382 <INPUT TYPE="HIDDEN" NAME="PlayerName" VALUE="<%=PlayerName%>"> 383 <INPUT TYPE="HIDDEN" NAME="Turn" VALUE="<%=Turn%>"> 384 <INPUT TYPE="HIDDEN" NAME="GameID" VALUE="<%=GameID%>"> 385 <TABLE BORDER=1 WIDTH="50%"> 386 <% If Turn < 10 Then %> 387 <CAPTION>Turn <%=Turn%> - <%=PlayerName%>'s Turn</CAPTION> 388 <% Else %> 389 <CAPTION>Game Over</CAPTION> 390 <% 391 End If 392 If GameID = "New Game" Then GameID = -1 393 sql = "SELECT * FROM TicTacToe WHERE game_id = " & GameID & " ORDER BY location " 394 Set RS = DBQuery(sql) 395 FOR I = 1 To 9 396 If I = 1 Then 397 Response.Write "<TR>" 398 End If 399 If Winner = "None" Then 400 If Not RS.EOF Then 401 If RS("location") = I Then 402 %> 403 <TD ALIGN="CENTER"><B><%=RS("player_char")%></B></TD> 404 <% 405 RS.MoveNext 406 Else 407 %> 408 <TD ALIGN="CENTER"><INPUT TYPE="Radio" NAME="TTT" VALUE="<%=I%>" onClick='document.Form1.submit();'></TD> 409 <% 410 End If 'RS("location") = I 411 Else 412 %> 413 <TD ALIGN="CENTER"><INPUT TYPE="Radio" NAME="TTT" VALUE="<%=I%>" onClick='document.Form1.submit();'></TD> 414 <% 415 End If 'RS.EOF 416 Else 'There is a Winner 417 If Not RS.EOF Then 418 If RS("location") = I Then 419 If InArray(I,WinLine) Then 420 %> 421 <TD ALIGN="CENTER"><FONT COLOR="Red"><B><%=RS("player_char")%></B></FONT></TD> 422 <% 423 Else 424 %> 425 <TD ALIGN="CENTER"><B><%=RS("player_char")%></B></TD> 426 427 <% 428 End If 429 RS.MoveNext 430 Else 431 %> 432 <TD ALIGN="CENTER"> </TD> 433 <% 434 End If 'RS("location") = I 435 Else 436 %> 437 <TD ALIGN="CENTER"> </TD> 438 <% 439 End If 'RS.EOF 440 End If 'Winner = None 441 If I = 3 OR I = 6 Then 442 Response.Write "</TR><TR>" 443 End If 444 If I = 9 Then 445 Response.Write "</TR>" 446 End If 447 Next 448 %> 449 </TABLE> 450 </FORM> 451 <% 452 sql = "SELECT * FROM TicTacToe WHERE game_id = " & GameID & " AND location < 10 ORDER BY turn " 453 Set RS = DBQuery(sql) 454 If Not RS.EOF Then 455 %> 456 <TABLE BORDER=1> 457 <CAPTION><B>Game History:</B> 458 <TR> 459 <TH>Player</TH> 460 <TH>Move</TH> 461 </TR> 462 <% 463 While Not RS.EOF 464 %> 465 <TR> 466 <TD><%=RS("player_name")%></TD> 467 <TD><%=RS("location")%></TD> 468 </TR> 469 <% 470 RS.MoveNext 471 Wend 472 %> 473 </TABLE> 474 <% End If 'RS.EOF History Table %> 475 <% End If %> 476 <% 477 Call ArticleFooter() 478 %>
This entire program took me less than a day to write, so there are almost certainly a few bugs
or gross inefficiencies in it. If you find any ways to improve the code, please let me know.
Also note that DBQuery is a function that is included in my top.asp include file, and its
function is rather obvious: it returns a recordset from my default SQL Server database.
|
|