Samples
Samples
TicTacToe
Language: Oxygene, Platform: Toffee, Category: UIKit
https://github.com/remobjects/ElementsSamples/tree/master/Oxygene/Toffee/UIKit/TicTacToe
-
TicTacToe
-
References
- CoreGraphics
- Foundation
- GameKit
- libToffee
- UIKit
- rtl
- Source Files
-
Other Files
- Resources\Game Images\Grid@2x.png
- Resources\Game Images\Grid.png
- Resources\Game Images\Paper@2x.png
- Resources\Game Images\Paper.png
- Resources\Game Images\O1.png
- Resources\Game Images\O1@2x.png
- Resources\Game Images\X1@2x.png
- Resources\Game Images\X1.png
- Resources\Game Images\O2@2x.png
- Resources\Game Images\O2.png
- Resources\Game Images\O3@2x.png
- Resources\Game Images\O3.png
- Resources\Game Images\O4@2x.png
- Resources\Game Images\O4.png
- Resources\Game Images\O5@2x.png
- Resources\Game Images\O5.png
- Resources\Game Images\X2@2x.png
- Resources\Game Images\X2.png
- Resources\Game Images\X3@2x.png
- Resources\Game Images\X3.png
- Resources\Game Images\X4@2x.png
- Resources\Game Images\X4.png
- Resources\Game Images\X5@2x.png
- Resources\Game Images\X5.png
- Resources\Info.plist
- Resources\App Icons\App-29.png
- Resources\App Icons\App-57.png
- Resources\App Icons\App-58.png
- Resources\App Icons\App-96.png
- Resources\App Icons\App-114.png
- Resources\App Icons\App-512.png
- Resources\App Icons\App-1024.png
- Resources\Launch Images\Default.png
- Resources\Launch Images\Default@2x.png
- Resources\Launch Images\Default-568h@2x.png
- RootViewController~iphone.xib
-
References
ComputerPlayer.pas
namespace TicTacToe;
interface
uses
Foundation;
type
ComputerPlayer = public class
private
fBoard: Board;
fComputerPlayer: String;
fForkSquares: Array[1..9] of NSInteger;
method playerAtCoordinates(x: Int32; y: Int32): String;
method OpponentInPosition(x, y : Int32):Boolean;
method ComputerInPosition(x, y : Int32):Boolean;
method OpponentInSquare(a : Int32):Boolean;
method ComputerInSquare(a : Int32):Boolean;
method EmptySquare(a : Int32):Boolean;
method XforPos(p : Int32):Int32;
method YforPos(p : Int32):Int32;
method WinningSquare(a: Int32; b: Int32; c: Int32): Int32;
method BlockingSquare(a: Int32; b: Int32; c: Int32): Int32;
method CheckFork(a: Int32; b: Int32; c: Int32);
method CheckForkBlock(a: Int32; b: Int32; c: Int32);
method CanPlay(a: Int32):Boolean;
method CanWin: Boolean;
method CanBlock: Boolean;
method CanFork: Boolean;
method CanBlockFork: Boolean;
method CanGoInCentre: Boolean;
method CanGoInOppositeCorner: Boolean;
method CanGoInEmptyCorner: Boolean;
method CanGoInEmptySide: Boolean;
protected
public
method makeBestMove(aPlayer: String; aBoard:Board);
method SetGridInfo(x, y : Int32; aPlayer:String);
end;
{ To make this clearer, the grid (which is in 2x2 array on the board) is referred to by number representing each of the nine squares, as follows:
1 | 2 | 3
---------
4 | 5 | 6
---------
7 | 8 | 9
The board calls makeBestMove which will work out the best location to go, and the board will go in this location.
This calls a series of possible moves in the order most likely to win the game (or at least, not lose).}
implementation
method ComputerPlayer.playerAtCoordinates(x, y: Int32): String;
begin
result := fBoard.GridInfo[x,y]:substringToIndex(1);
end;
method ComputerPlayer.OpponentInPosition(x, y : Int32):Boolean;
begin
result:=assigned(fBoard.GridInfo[x,y]) and (playerAtCoordinates(x, y) <> fComputerPlayer);
end;
method ComputerPlayer.ComputerInPosition(x, y : Int32):Boolean;
begin
result:=assigned(fBoard.GridInfo[x,y]) and (playerAtCoordinates(x, y) = fComputerPlayer);
end;
method ComputerPlayer.OpponentInSquare(a: Int32): Boolean;
begin
var x : Int32 := XforPos(a);
var y : Int32 := YforPos(a);
exit OpponentInPosition(x ,y);
end;
method ComputerPlayer.ComputerInSquare(a: Int32): Boolean;
begin
var x : Int32 := XforPos(a);
var y : Int32 := YforPos(a);
exit ComputerInPosition(x ,y);
end;
method ComputerPlayer.EmptySquare(a : Int32):Boolean;
begin
var x : Int32 := XforPos(a);
var y : Int32 := YforPos(a);
exit not assigned(fBoard.GridInfo[x,y]);
end;
method ComputerPlayer.XforPos(p: Int32): Int32;
begin
if p in [1,2,3] then exit 0
else if p in [4,5,6] then exit 1
else if p in [7,8,9] then exit 2;
end;
method ComputerPlayer.YforPos(p: Int32): Int32;
begin
if p in [1,4,7] then exit 0
else if p in [2,5,8] then exit 1
else if p in [3,6,9] then exit 2;
end;
method ComputerPlayer.WinningSquare(a,b,c : Int32):Int32; //lookup to see if one of the squares in the triple is available to win
begin
if ComputerInSquare(a) and ComputerInSquare(b) and EmptySquare(c) then exit c
else if ComputerInSquare(a) and ComputerInSquare(c) and EmptySquare(b) then exit b
else if ComputerInSquare(b) and ComputerInSquare(c) and EmptySquare(a) then exit a
else exit 0;
end;
method ComputerPlayer.BlockingSquare(a,b,c : Int32):Int32;//lookup to see if one of the three is available for opponent to win
begin
if OpponentInSquare(a) and OpponentInSquare(b) and EmptySquare(c) then exit c
else if OpponentInSquare(a) and OpponentInSquare(c) and EmptySquare(b) then exit b
else if OpponentInSquare(b) and OpponentInSquare(c) and EmptySquare(a) then exit a
else exit 0;
end;
method ComputerPlayer.CheckFork(a: Int32; b: Int32; c: Int32);
begin
if ComputerInSquare(a) and EmptySquare(b) and EmptySquare(c) then begin
inc(fForkSquares[b]);
inc(fForkSquares[c]);
end;
if ComputerInSquare(b) and EmptySquare(a) and EmptySquare(c) then begin
inc(fForkSquares[a]);
inc(fForkSquares[c]);
end;
if ComputerInSquare(c) and EmptySquare(b) and EmptySquare(a) then begin
inc(fForkSquares[b]);
inc(fForkSquares[a]);
end;
end;
method ComputerPlayer.CheckForkBlock(a: Int32; b: Int32; c: Int32);
begin
if OpponentInSquare(a) and EmptySquare(b) and EmptySquare(c) then begin
inc(fForkSquares[b]);
inc(fForkSquares[c]);
end;
if OpponentInSquare(b) and EmptySquare(a) and EmptySquare(c) then begin
inc(fForkSquares[a]);
inc(fForkSquares[c]);
end;
if OpponentInSquare(c) and EmptySquare(b) and EmptySquare(a) then begin
inc(fForkSquares[b]);
inc(fForkSquares[a]);
end;
end;
method ComputerPlayer.CanPlay(a : Int32):Boolean;
begin
if a=0 then exit false;
var x : Int32 := XforPos(a);
var y : Int32 := YforPos(a);
if not assigned(fBoard.GridInfo[x,y]) then begin
fBoard.markGrid(x, y, fComputerPlayer);
result:=True;
end else result:=false;
end;
method ComputerPlayer.CanWin:Boolean;//User isn't concentrating
begin
//the number triple is a potential winning line (there aren't many)
result:=CanPlay(WinningSquare(1,2,3)) or
CanPlay(WinningSquare(4,5,6)) or
CanPlay(WinningSquare(7,8,9)) or
CanPlay(WinningSquare(1,4,7)) or
CanPlay(WinningSquare(2,5,8)) or
CanPlay(WinningSquare(3,6,9)) or
CanPlay(WinningSquare(1,5,9)) or
CanPlay(WinningSquare(3,5,7));
end;
method ComputerPlayer.CanBlock:Boolean;//Stop the user winning
begin
result:=CanPlay(BlockingSquare(1,2,3)) or
CanPlay(BlockingSquare(4,5,6)) or
CanPlay(BlockingSquare(7,8,9)) or
CanPlay(BlockingSquare(1,4,7)) or
CanPlay(BlockingSquare(2,5,8)) or
CanPlay(BlockingSquare(3,6,9)) or
CanPlay(BlockingSquare(1,5,9)) or
CanPlay(BlockingSquare(3,5,7));
end;
method ComputerPlayer.CanFork:Boolean;
begin
//a fork is where the same square appears in two triples that could be a winning line
//so we need to find the empty square numbers a triple has the computer in the one square and the other two are empty
//then see if a number appears more than once in the array, which means it is a pivot for the fork
for i:Int32 :=1 to 9 do fForkSquares[i]:=0;
CheckFork(1,2,3);
CheckFork(4,5,6);
CheckFork(7,8,9);
CheckFork(1,4,7);
CheckFork(2,5,8);
CheckFork(3,6,9);
CheckFork(1,5,9);
CheckFork(3,5,7);
//now check if any are 2 or more and select first one available
for i:Int32 :=1 to 9 do
if ((fForkSquares[i]>1) and CanPlay(i)) then exit true;
exit false;
end;
method ComputerPlayer.CanBlockFork:Boolean;
begin
//Same as for a fork, but for the opponent, we need to prevent it
for i:Int32 :=1 to 9 do fForkSquares[i]:=0;
CheckForkBlock(1,2,3);
CheckForkBlock(4,5,6);
CheckForkBlock(7,8,9);
CheckForkBlock(1,4,7);
CheckForkBlock(2,5,8);
CheckForkBlock(3,6,9);
CheckForkBlock(1,5,9);
CheckForkBlock(3,5,7);
//now check if any are 2 or more and select first one available
for i:Int32 :=1 to 9 do
if ((fForkSquares[i]>1) and CanPlay(i)) then exit true;
exit false;
end;
method ComputerPlayer.CanGoInCentre:Boolean;
begin
result:=CanPlay(5);
end;
method ComputerPlayer.CanGoInOppositeCorner:Boolean;
begin
result:=(OpponentInSquare(1) and CanPlay(9))or
(OpponentInSquare(3) and CanPlay(7))or
(OpponentInSquare(7) and CanPlay(3))or
(OpponentInSquare(9) and CanPlay(1));
end;
method ComputerPlayer.CanGoInEmptyCorner:Boolean;
begin
result:=CanPlay(1) or CanPlay(3) or CanPlay(7) or CanPlay(7);
end;
method ComputerPlayer.CanGoInEmptySide:Boolean;
begin
result:=CanPlay(2) or CanPlay(4) or CanPlay(6) or CanPlay(8);
end;
method ComputerPlayer.makeBestMove(aPlayer: String; aBoard:Board);
begin
fComputerPlayer := aPlayer;
fBoard := aBoard;
if CanWin or
CanBlock or
CanFork or
CanBlockFork or
CanGoInCentre or
CanGoInOppositeCorner or
CanGoInEmptyCorner or
CanGoInEmptySide then;
end;
method ComputerPlayer.SetGridInfo(x: Int32; y: Int32; aPlayer: String);
begin
fBoard.markGrid(x, y, aPlayer);
end;
end.
