Skip to main content

Exercise: Write a Tic-Tac-Toe game

A possible solution is at the end of this page.

Try it yourself

This is your first assignment, to exercise what you just learned. In order to complete this task, use the documentation to read about verbs, functions, etc., and get familiar with UI programming in BBj.

Write a two-placer Tic-Tac-Toe game in BBj. Create a board layout that can take user input with mouse clicks, shows the player who is up for the next move. Your game should check with every move if one of the players won.

If you don't know Tic Tac Toe yet: https://en.wikipedia.org/wiki/Tic-tac-toe

Possible solution

The original course had no solution for this exercise, so this one was written for this book. It uses only plain BBj controls, button callbacks and process_events, without CSS, and it also runs in the DWC. The solution is in TicTacToe.bbj, and you find all files in the exercises.zip link.

TicTacToe.bbj
rem TicTacToe.bbj
rem Possible solution for the exercise Write a Tic-Tac-Toe game, written for the Introduction to BBj Development book
rem Two players take turns at one screen. It uses plain BBj controls and callbacks, without CSS, and also runs in the DWC.

declare BBjAPI api!
declare BBjSysGui sysgui!
declare BBjTopLevelWindow wnd!
declare BBjButton btn!
declare BBjStaticText status!
declare BBjVector cells!

api! = BBjAPI()
sysgui! = api!.openSysGui("X0")
wnd! = sysgui!.addWindow(100,100,320,400,"Tic-Tac-Toe")

rem the nine cell buttons get the control IDs 101 to 109, laid out in three rows of three
cells! = api!.makeVector()
for i = 0 to 8
btn! = wnd!.addButton(101+i,10+mod(i,3)*100,10+int(i/3)*100,95,95,"")
btn!.setCallback(BBjAPI.ON_BUTTON_PUSH,"cellPushed")
cells!.addItem(btn!)
next i

status! = wnd!.addStaticText(110,10,315,300,25,"")
btn! = wnd!.addButton(111,10,350,300,30,"New game")
btn!.setCallback(BBjAPI.ON_BUTTON_PUSH,"newGame")

wnd!.setCallback(BBjAPI.ON_CLOSE,"byebye")

rem the eight winning lines as cell numbers: three rows, three columns, two diagonals
winLines$ = "123456789147258369159357"

gosub resetGame

process_events

cellPushed:
rem the pushed button tells us its control ID, cell 1 has ID 101
ev! = sysgui!.getLastEvent()
ctrl! = ev!.getControl()
cell = ctrl!.getID() - 100

rem ignore a click on a taken cell and every click after the game has ended
if (gameOver <> 0) or (board$[cell] <> "") then
return
endif

board$[cell] = player$
cellBtn! = cells!.getItem(cell-1)
cellBtn!.setText(player$)
moves = moves + 1

rem the win check comes first, so a ninth move that completes a line is a win and not a draw
gosub checkWinner
if winner$ <> "" then
status!.setText("Player "+winner$+" wins!")
gameOver = 1
else
if moves = 9 then
status!.setText("It's a draw.")
gameOver = 1
else
if player$ = "X" then
player$ = "O"
else
player$ = "X"
endif
status!.setText("Player "+player$+" is up")
endif
endif
return

checkWinner:
rem look at each line in the table: three cell numbers, all holding the same mark
winner$ = ""
for k = 0 to 7
a = num(winLines$(k*3+1,1))
b = num(winLines$(k*3+2,1))
c = num(winLines$(k*3+3,1))
if (board$[a] <> "") and (board$[a] = board$[b]) and (board$[a] = board$[c]) then
winner$ = board$[a]
endif
next k
return

newGame:
gosub resetGame
return

resetGame:
rem board$[1] to board$[9] hold "X", "O" or an empty string for a free cell
dim board$[9]
player$ = "X"
moves = 0
gameOver = 0
for i = 1 to 9
cellBtn! = cells!.getItem(i-1)
cellBtn!.setText("")
next i
status!.setText("Player X is up")
return

byebye:
release