Tic-tac-toe: Difference between revisions

6,825 bytes added ,  11 months ago
no edit summary
m (The name of the game is spelled "noughts and crosses". While the spelling "naught" took over as the general synonym for "nothing", "nought" is still used to refer to zero as a figure (0).)
No edit summary
Line 4,445:
 
You win!</pre>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
This is a GUI, event driven version of the game. The game board is a "TStringGrid" component, which has a grid that can hold and display characters. In this case, the grid displays Xs and Ox using a large font.
 
When the user clicks on the grid, this generates an event that is handled by the program. The mouse click coordinates are converted to a cell coordinates and a large X is placed in the box. At this point program tests if this resulted in a win. Next it calculate the computer's response and it checks to see if the computer won. The process is repeated until there is a winner or a draw.
 
 
 
<syntaxhighlight lang="Delphi">
{Array contain possiple winning lines}
 
type TWinLine = array [0..3-1] of TPoint;
 
var WinLines: array [0..8-1] of TWinLine = (
((X:0; Y:0), (X:1; Y:0), (X:2; Y:0)),
((X:0; Y:1), (X:1; Y:1), (X:2; Y:1)),
((X:0; Y:2), (X:1; Y:2), (X:2; Y:2)),
((X:0; Y:0), (X:0; Y:1), (X:0; Y:2)),
((X:1; Y:0), (X:1; Y:1), (X:1; Y:2)),
((X:2; Y:0), (X:2; Y:1), (X:2; Y:2)),
((X:0; Y:0), (X:1; Y:1), (X:2; Y:2)),
((X:2; Y:0), (X:1; Y:1), (X:0; Y:2))
);
 
 
{Array containing all characters in a line}
 
type TCellArray = array [0..3-1] of char;
 
var WinLineInx: integer;
var GameOver: boolean;
 
procedure ClearGrid;
{Clear TTT Grid by setting all cells to a space}
var X,Y: integer;
begin
with TicTacToeDlg do
begin
for Y:=0 to GameGrid.RowCount-1 do
for X:=0 to GameGrid.ColCount-1 do GameGrid.Cells[X,Y]:=' ';
WinLineInx:=-1;
Status1Dis.Caption:='';
GameOver:=False;
end;
 
end;
 
 
function FirstEmptyCell(var P: TPoint): boolean;
{Find first empty grid i.e. the one containing a space}
{Returns false if there are no empty cells (a tie game)}
var X,Y: integer;
begin
Result:=True;
with TicTacToeDlg do
begin
{Iterate through all cells in array}
for Y:=0 to GameGrid.RowCount-1 do
for X:=0 to GameGrid.ColCount-1 do
if GameGrid.Cells[X,Y]=' ' then
begin
P.X:=X; P.Y:=Y;
Exit;
end;
end;
Result:=False;
end;
 
 
 
procedure GetLineChars(Inx: integer; var CA: TCellArray);
{Get all the characters in a specific win line}
var P1,P2,P3: TPoint;
begin
with TicTacToeDlg do
begin
{Get cell position of specific win line}
P1:=WinLines[Inx,0];
P2:=WinLines[Inx,1];
P3:=WinLines[Inx,2];
{Get the characters from each and put in array}
CA[0]:=GameGrid.Cells[P1.X,P1.Y][1];
CA[1]:=GameGrid.Cells[P2.X,P2.Y][1];
CA[2]:=GameGrid.Cells[P3.X,P3.Y][1];
end;
end;
 
 
 
function IsWinner(var Inx: integer; var C: char): boolean;
{Test if the specified line is a winner}
{Return index of line and the char of winner}
var I,J: integer;
var CA: TCellArray;
begin
with TicTacToeDlg do
begin
Result:=False;
{Go through all winning patterns}
for J:=0 to High(WinLines) do
begin
{Get one winning pattern}
GetLineChars(J,CA);
{Look for line that has the same char in all three places}
if (CA[0]<>' ') and (CA[0]=CA[1]) and (CA[0]=CA[2]) then
begin
Result:=True;
Inx:=J;
C:=CA[0];
end;
end;
 
end;
end;
 
 
procedure DrawWinLine(Inx: integer);
{Draw line through winning squares}
var Line: TWinLine;
var C1,C2: TPoint;
var P1,P2: TPoint;
var W2,H2: integer;
begin
with TicTacToeDlg do
begin
{Offset to center of cell}
W2:=GameGrid.ColWidths[0] div 2;
H2:=GameGrid.RowHeights[0] div 2;
{Get winning pattern of lines}
Line:=WinLines[Inx];
{Get beginning and ending cell of win}
C1:=Line[0]; C2:=Line[2];
{Convert to screen coordinates}
P1.X:=C1.X * GameGrid.ColWidths[0] + W2;
P1.Y:=C1.Y * GameGrid.RowHeights[0] + H2;
P2.X:=C2.X * GameGrid.ColWidths[0] + W2;
P2.Y:=C2.Y * GameGrid.RowHeights[0] + H2;
{Set line attributes}
GameGrid.Canvas.Pen.Color:=clRed;
GameGrid.Canvas.Pen.Width:=5;
{Draw line}
GameGrid.Canvas.MoveTo(P1.X,P1.Y);
GameGrid.Canvas.LineTo(P2.X,P2.Y);
end;
end;
 
 
 
procedure DoBestComputerMove;
{Analyze game board and execute the best computer move}
var I,J,Inx: integer;
var CA: TCellArray;
var P: TPoint;
 
 
function UrgentMove(CA: TCellArray; var EmptyInx: integer): boolean;
{Test row, column or diagonal for an urgent move}
{This would be either an immediate win or immediate loss}
{Returns True if there is an urgent move and the index of location to respond}
var I: integer;
var OCnt,XCnt,EmptyCnt: integer;
begin
Result:=False;
OCnt:=0; XCnt:=0;
EmptyCnt:=0; EmptyInx:=-1;
{Count number of Xs, Os or Spaces in line}
for I:=0 to High(CA) do
begin
case CA[I] of
'O': Inc(OCnt);
'X': Inc(XCnt);
' ':
begin
Inc(EmptyCnt);
if EmptyCnt=1 then EmptyInx:=I;
end;
end;
end;
{Look for pattern of one empty and two Xs or two Os}
{Which means it's one move away from a win}
Result:=(EmptyCnt=1) and ((OCnt=2) or (XCnt=2));
end;
 
 
begin
with TicTacToeDlg do
begin
{Look for urgent moves in all patterns of wins}
for J:=0 to High(WinLines) do
begin
{Get a winning pattern of chars}
GetLineChars(J,CA);
if UrgentMove(CA,Inx) then
begin
{Urgent move found - take it}
P:=WinLines[J,Inx];
GameGrid.Cells[P.X,P.Y]:='O';
exit;
end;
end;
{No urgent moves, so use first empty}
{If there is no empty, the game is stalemated}
if FirstEmptyCell(P) then GameGrid.Cells[P.X,P.Y]:='O';
end;
end;
 
 
function TestWin: boolean;
{Test if last move resulted in win/draw}
var Inx: integer; var C: char;
var P: TPoint;
var S: string;
begin
Result:=True;
{Test if somebody won}
if IsWinner(Inx,C) then
begin
WinLineInx:=Inx;
TicTacToeDlg.GameGrid.Invalidate;
if C='O' then S:=' Computer Won!!' else S:=' You Won!!';
TicTacToeDlg.Status1Dis.Caption:=S;
GameOver:=True;
exit;
end;
{Test if game is a draw}
if not FirstEmptyCell(P) then
begin
TicTacToeDlg.Status1Dis.Caption:=' Game is Draw.';
GameOver:=True;
exit;
end;
Result:=False;
end;
 
 
procedure PlayTicTacToe;
{Show TicTacToe dialog box}
begin
ClearGrid;
TicTacToeDlg.ShowModal
end;
 
 
 
procedure TTicTacToeDlg.GameGridMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
{Handle user click on TicTacToe grid}
var Row,Col: integer;
begin
with TicTacToeDlg do
begin
if GameOver then exit;;
{Convert Mouse X,Y to Grid row and column}
GameGrid.MouseToCell(X,Y,Col,Row);
{Mark user's selection by placing X in the cell}
if GameGrid.Cells[Col,Row]=' 'then
GameGrid.Cells[Col,Row]:='X';
{Did this result in a win? }
if TestWin then exit;
{Get computer's response}
DoBestComputerMove;
{Did computer win}
TestWin;
end;
end;
 
procedure TTicTacToeDlg.ReplayBtnClick(Sender: TObject);
begin
ClearGrid;
end;
 
 
 
procedure TTicTacToeDlg.GameGridDrawCell(Sender: TObject; ACol,
ARow: Integer; Rect: TRect; State: TGridDrawState);
{Draw winner line on top of Xs and Os}
begin
if WinLineInx>=0 then DrawWinLine(WinLineInx);
end;
 
 
 
</syntaxhighlight>
{{out}}
<pre>
 
Elapsed Time: 19.126 Sec.
 
</pre>
 
 
=={{header|EasyLang}}==
465

edits