MatanH
06-09-2008, 03:48 PM
Just wanted to share with you this Tic Tac Toe Game I've written for fun..
-- Written by: Matan Halberstadt
-- Date: Monday 09, June 2008.
-- Contact: Halbertism@Gmail.com
-- http://halbertism.com
--*******************************************
try destroyDialog TTTRollout catch ()
rollout TTTRollout "TTT"
(
-- Local Variable Declerations
------------------------------------------
local dim = 120
local valArr
local testValArr
local sequence
local tickTest = false
-- User Interface
------------------------------------------
button bn02 "" width:(dim/3) height:(dim/3) align:#center
button bn01 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y]
button bn03 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y]
button bn04 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim/3]
button bn05 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim/3]
button bn06 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim/3]
button bn07 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim*2/3]
button bn08 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim*2/3]
button bn09 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim*2/3]
button bnNext "Next Turn" width:dim align:#center enabled:false
button bnRestart "Restart" width:dim align:#center
label lbWins " Wins:" align:#left
label lbLosts "Losts: " align:#right offset:[0,-18]
spinner spWins "" fieldWidth:40 align:#left type:#integer enabled:false
spinner spLosts "" fieldWidth:40 align:#right type:#integer offset:[0,-22] enabled:false
timer tmEnd interval:100 active:false
-- Functions
------------------------------------------
fn updateUI =
(
fn getLabel lin row =
(
local label = ""
if valArr[lin][row] > 0 then label = "X"
if valArr[lin][row] < 0 then label = "O"
label
)
bn01.enabled = (bn01.caption = getLabel 1 1).count == 0
bn02.enabled = (bn02.caption = getLabel 1 2).count == 0
bn03.enabled = (bn03.caption = getLabel 1 3).count == 0
bn04.enabled = (bn04.caption = getLabel 2 1).count == 0
bn05.enabled = (bn05.caption = getLabel 2 2).count == 0
bn06.enabled = (bn06.caption = getLabel 2 3).count == 0
bn07.enabled = (bn07.caption = getLabel 3 1).count == 0
bn08.enabled = (bn08.caption = getLabel 3 2).count == 0
bn09.enabled = (bn09.caption = getLabel 3 3).count == 0
if bnRestart.caption != "Restart" then bnNext.enabled = false
)
fn testGameEnd vArr readOnly:false =
(
local test = 0
sequence = #()
for a = 1 to 3 do (
if vArr[a][1] == vArr[a][2] and vArr[a][1] == vArr[a][3] then
(
if vArr[a][1] > 0 then test = 1
if vArr[a][1] < 0 then test = -1
if vArr[a][1] != 0 then sequence = #([a,1],[a,2],[a,3])
)
if vArr[1][a] == vArr[2][a] and vArr[1][a] == vArr[3][a] then
(
if vArr[1][a] > 0 then test = 1
if vArr[1][a] < 0 then test = -1
if vArr[1][a] != 0 then sequence = #([1,a],[2,a],[3,a])
)
) --end a loop
if vArr[1][1] == vArr[2][2] and vArr[1][1] == vArr[3][3] then
(
if vArr[1][1] > 0 then test = 1
if vArr[1][1] < 0 then test = -1
if vArr[1][1] != 0 then sequence = #([1,1],[2,2],[3,3])
)
if vArr[1][3] == vArr[2][2] and vArr[1][3] == vArr[3][1] then
(
if vArr[1][3] > 0 then test = 1
if vArr[1][3] < 0 then test = -1
if vArr[1][3] != 0 then sequence = #([1,3],[2,2],[3,1])
)
if test == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if test == 0 and vArr[lin][row] == 0 then test = 2
)
)
)
if not readOnly then (
case of
(
(test == 0):
(
bnRestart.caption = "Tie!"
)
(test == 1):
(
bnRestart.caption = "You Win!"
spWins.value += 1
)
(test == -1):
(
bnRestart.caption = "You Lose!"
spLosts.value += 1
)
defalut:
(
bnRestart.caption = "Restart"
)
)
if sequence.count == 3 then tmEnd.active = true
)
test
)
fn setMatrix lin row val force:false =
(
if (not bnNext.enabled or force) and bnRestart.caption == "Restart" then (
valArr[lin][row] = val
bnNext.enabled = not bnNext.enabled
testGameEnd valArr
updateUI()
)
)
fn calculateMove =
(
local posibleMoves = #()
-- [1] Win posibility test:
--------------------------------
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
if testGameEnd valArr readOnly:true == -1 then (
append posibleMoves [lin,row]
format "Win\n"
)
valArr[lin][row] = 0
)
)
)
-- [2] Block posibility test:
---------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
if testGameEnd valArr readOnly:true == 1 then (
append posibleMoves [lin,row]
format "Block\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [3] Fork posibility test:
--------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = -1
if testGameEnd valArr readOnly:true == -1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Fork posibility\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [4] Block Fork posibility test:
----------------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = 1
if testGameEnd valArr readOnly:true == 1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Block Fork posibility\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [5] Empty Centre posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
if valArr[2][2] == 0 then (
append posibleMoves [2,2]
format "Empty Centre\n"
)
)
-- [6] Opposite Corner posibility test:
------------------------------------------------
if posibleMoves.count == 0 then (
local sides = #([1,1],[1,3],[3,1],[3,3])
for a = 1 to sides.count do (
if valArr[sides[a].x][sides[a].y] == 1 then (
b = 5 - a
if valArr[sides[b].x][sides[b].y] == 0 then (
append posibleMoves sides[b]
format "Opposite Corner\n"
)
)
)
)
-- [7] Empty Corner posibility test:
-----------------------------------------
if posibleMoves.count == 0 then (
local corners = #([1,1],[1,3],[3,1],[3,3])
for i in corners do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Corner\n"
)
)
)
-- [8] Empty Side posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
local sides = #([1,2],[2,1],[2,3],[3,2])
for i in sides do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Side\n"
)
)
)
-- Make a move:
---------------------
local newMove = posibleMoves[random 1 posibleMoves.count]
setMatrix newMove.x newMove.y -1 force:true
)
fn nextTurn =
(
calculateMove()
updateUI()
)
fn restartGame =
(
tmEnd.active = true
valArr = #(#(0,0,0),#(0,0,0),#(0,0,0))
bnRestart.caption = "Restart"
bnNext.enabled = false
updateUI()
)
fn showWinner =
(
if bnRestart.caption == "You Win!" or bnRestart.caption == "You Lose!" then (
local char = if bnRestart.caption == "You Win!" then "X" else "O"
for i in sequence do (
if i == [1,1] then bn01.caption = if tickTest then char else ""
if i == [1,2] then bn02.caption = if tickTest then char else ""
if i == [1,3] then bn03.caption = if tickTest then char else ""
if i == [2,1] then bn04.caption = if tickTest then char else ""
if i == [2,2] then bn05.caption = if tickTest then char else ""
if i == [2,3] then bn06.caption = if tickTest then char else ""
if i == [3,1] then bn07.caption = if tickTest then char else ""
if i == [3,2] then bn08.caption = if tickTest then char else ""
if i == [3,3] then bn09.caption = if tickTest then char else ""
)
tickTest = not tickTest
)
)
fn openDialog =
(
createDialog TTTRollout width:(dim + 25)
)
fn init =
(
restartGame()
)
fn done =
(
-- cleanup code
gc light:true
)
-- Event Handlers
------------------------------------------
on bn01 pressed do setMatrix 1 1 1
on bn02 pressed do setMatrix 1 2 1
on bn03 pressed do setMatrix 1 3 1
on bn04 pressed do setMatrix 2 1 1
on bn05 pressed do setMatrix 2 2 1
on bn06 pressed do setMatrix 2 3 1
on bn07 pressed do setMatrix 3 1 1
on bn08 pressed do setMatrix 3 2 1
on bn09 pressed do setMatrix 3 3 1
on bnRestart pressed do restartGame()
on bnNext pressed do nextTurn()
on tmEnd tick do showWinner()
on TTTRollout open do init()
on TTTRollout close do done()
) -- end of rollout
TTTRollout.openDialog()
-- Written by: Matan Halberstadt
-- Date: Monday 09, June 2008.
-- Contact: Halbertism@Gmail.com
-- http://halbertism.com
--*******************************************
try destroyDialog TTTRollout catch ()
rollout TTTRollout "TTT"
(
-- Local Variable Declerations
------------------------------------------
local dim = 120
local valArr
local testValArr
local sequence
local tickTest = false
-- User Interface
------------------------------------------
button bn02 "" width:(dim/3) height:(dim/3) align:#center
button bn01 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y]
button bn03 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y]
button bn04 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim/3]
button bn05 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim/3]
button bn06 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim/3]
button bn07 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim*2/3]
button bn08 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim*2/3]
button bn09 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim*2/3]
button bnNext "Next Turn" width:dim align:#center enabled:false
button bnRestart "Restart" width:dim align:#center
label lbWins " Wins:" align:#left
label lbLosts "Losts: " align:#right offset:[0,-18]
spinner spWins "" fieldWidth:40 align:#left type:#integer enabled:false
spinner spLosts "" fieldWidth:40 align:#right type:#integer offset:[0,-22] enabled:false
timer tmEnd interval:100 active:false
-- Functions
------------------------------------------
fn updateUI =
(
fn getLabel lin row =
(
local label = ""
if valArr[lin][row] > 0 then label = "X"
if valArr[lin][row] < 0 then label = "O"
label
)
bn01.enabled = (bn01.caption = getLabel 1 1).count == 0
bn02.enabled = (bn02.caption = getLabel 1 2).count == 0
bn03.enabled = (bn03.caption = getLabel 1 3).count == 0
bn04.enabled = (bn04.caption = getLabel 2 1).count == 0
bn05.enabled = (bn05.caption = getLabel 2 2).count == 0
bn06.enabled = (bn06.caption = getLabel 2 3).count == 0
bn07.enabled = (bn07.caption = getLabel 3 1).count == 0
bn08.enabled = (bn08.caption = getLabel 3 2).count == 0
bn09.enabled = (bn09.caption = getLabel 3 3).count == 0
if bnRestart.caption != "Restart" then bnNext.enabled = false
)
fn testGameEnd vArr readOnly:false =
(
local test = 0
sequence = #()
for a = 1 to 3 do (
if vArr[a][1] == vArr[a][2] and vArr[a][1] == vArr[a][3] then
(
if vArr[a][1] > 0 then test = 1
if vArr[a][1] < 0 then test = -1
if vArr[a][1] != 0 then sequence = #([a,1],[a,2],[a,3])
)
if vArr[1][a] == vArr[2][a] and vArr[1][a] == vArr[3][a] then
(
if vArr[1][a] > 0 then test = 1
if vArr[1][a] < 0 then test = -1
if vArr[1][a] != 0 then sequence = #([1,a],[2,a],[3,a])
)
) --end a loop
if vArr[1][1] == vArr[2][2] and vArr[1][1] == vArr[3][3] then
(
if vArr[1][1] > 0 then test = 1
if vArr[1][1] < 0 then test = -1
if vArr[1][1] != 0 then sequence = #([1,1],[2,2],[3,3])
)
if vArr[1][3] == vArr[2][2] and vArr[1][3] == vArr[3][1] then
(
if vArr[1][3] > 0 then test = 1
if vArr[1][3] < 0 then test = -1
if vArr[1][3] != 0 then sequence = #([1,3],[2,2],[3,1])
)
if test == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if test == 0 and vArr[lin][row] == 0 then test = 2
)
)
)
if not readOnly then (
case of
(
(test == 0):
(
bnRestart.caption = "Tie!"
)
(test == 1):
(
bnRestart.caption = "You Win!"
spWins.value += 1
)
(test == -1):
(
bnRestart.caption = "You Lose!"
spLosts.value += 1
)
defalut:
(
bnRestart.caption = "Restart"
)
)
if sequence.count == 3 then tmEnd.active = true
)
test
)
fn setMatrix lin row val force:false =
(
if (not bnNext.enabled or force) and bnRestart.caption == "Restart" then (
valArr[lin][row] = val
bnNext.enabled = not bnNext.enabled
testGameEnd valArr
updateUI()
)
)
fn calculateMove =
(
local posibleMoves = #()
-- [1] Win posibility test:
--------------------------------
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
if testGameEnd valArr readOnly:true == -1 then (
append posibleMoves [lin,row]
format "Win\n"
)
valArr[lin][row] = 0
)
)
)
-- [2] Block posibility test:
---------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
if testGameEnd valArr readOnly:true == 1 then (
append posibleMoves [lin,row]
format "Block\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [3] Fork posibility test:
--------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = -1
if testGameEnd valArr readOnly:true == -1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Fork posibility\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [4] Block Fork posibility test:
----------------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = 1
if testGameEnd valArr readOnly:true == 1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Block Fork posibility\n"
)
valArr[lin][row] = 0
)
)
)
)
-- [5] Empty Centre posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
if valArr[2][2] == 0 then (
append posibleMoves [2,2]
format "Empty Centre\n"
)
)
-- [6] Opposite Corner posibility test:
------------------------------------------------
if posibleMoves.count == 0 then (
local sides = #([1,1],[1,3],[3,1],[3,3])
for a = 1 to sides.count do (
if valArr[sides[a].x][sides[a].y] == 1 then (
b = 5 - a
if valArr[sides[b].x][sides[b].y] == 0 then (
append posibleMoves sides[b]
format "Opposite Corner\n"
)
)
)
)
-- [7] Empty Corner posibility test:
-----------------------------------------
if posibleMoves.count == 0 then (
local corners = #([1,1],[1,3],[3,1],[3,3])
for i in corners do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Corner\n"
)
)
)
-- [8] Empty Side posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
local sides = #([1,2],[2,1],[2,3],[3,2])
for i in sides do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Side\n"
)
)
)
-- Make a move:
---------------------
local newMove = posibleMoves[random 1 posibleMoves.count]
setMatrix newMove.x newMove.y -1 force:true
)
fn nextTurn =
(
calculateMove()
updateUI()
)
fn restartGame =
(
tmEnd.active = true
valArr = #(#(0,0,0),#(0,0,0),#(0,0,0))
bnRestart.caption = "Restart"
bnNext.enabled = false
updateUI()
)
fn showWinner =
(
if bnRestart.caption == "You Win!" or bnRestart.caption == "You Lose!" then (
local char = if bnRestart.caption == "You Win!" then "X" else "O"
for i in sequence do (
if i == [1,1] then bn01.caption = if tickTest then char else ""
if i == [1,2] then bn02.caption = if tickTest then char else ""
if i == [1,3] then bn03.caption = if tickTest then char else ""
if i == [2,1] then bn04.caption = if tickTest then char else ""
if i == [2,2] then bn05.caption = if tickTest then char else ""
if i == [2,3] then bn06.caption = if tickTest then char else ""
if i == [3,1] then bn07.caption = if tickTest then char else ""
if i == [3,2] then bn08.caption = if tickTest then char else ""
if i == [3,3] then bn09.caption = if tickTest then char else ""
)
tickTest = not tickTest
)
)
fn openDialog =
(
createDialog TTTRollout width:(dim + 25)
)
fn init =
(
restartGame()
)
fn done =
(
-- cleanup code
gc light:true
)
-- Event Handlers
------------------------------------------
on bn01 pressed do setMatrix 1 1 1
on bn02 pressed do setMatrix 1 2 1
on bn03 pressed do setMatrix 1 3 1
on bn04 pressed do setMatrix 2 1 1
on bn05 pressed do setMatrix 2 2 1
on bn06 pressed do setMatrix 2 3 1
on bn07 pressed do setMatrix 3 1 1
on bn08 pressed do setMatrix 3 2 1
on bn09 pressed do setMatrix 3 3 1
on bnRestart pressed do restartGame()
on bnNext pressed do nextTurn()
on tmEnd tick do showWinner()
on TTTRollout open do init()
on TTTRollout close do done()
) -- end of rollout
TTTRollout.openDialog()
