TicTacToe in roblox studio--OOP style

// TicTacToe Class located in ServerStorage

local Prototype = {}
Prototype._index = Prototype

Prototype.currentPlayerMark = 'x';

function Prototype.new()
	local O = {}
	O.currentPlayerMark = 'x'
	O.board = {}
	for i = 1,3 do
		O.board[i] = {}
		for j = 1,3 do
			O.board[i][j] = '_'
		end
	end
	setmetatable(O, Prototype)
	return O
end

function Prototype.initializeBoard(self)
	for i = 1,3 do
		for j = 1,3  do
			self.Board[i][j] = '_'
		end
	end
end

function Prototype.checkRowCol(c1, c2, c3)
	return c1 ~= '_' and c1 == c2 and c2 == c3
end

function Prototype.checkRowsForWin(self)
	for i = 1,3 do
		if Prototype.checkRowCol(self.Board[i][1], self.Board[i][2], self.Board[i][3]) == true  then
			return true;
		end
	end
	return false;
end

function Prototype.checkColForWin(self)
	for i = 1,3 do
		if Prototype.checkRowCol(self.Board[1][i], self.Board[2][i], self.Board[3][i]) == true  then
			return true;
		end
	end
	return false;
end

function Prototype.checkDiagonalsForWin(self)
	return Prototype.checkRowCol(self.board[1][1], self.board[2][2], self.board[3][3]) == true or Prototype.checkRowCol(self.board[1][3], self.board[2][2], self.board[3][1]) == true
end

function Prototype.checkForWin(self)
	return self.checkRowsForWin() or self.checkColForWin() or self.checkDiagonalsForWin()
end

function Prototype.isBoardFull(self)
	local isFull = true;
	
	for i = 1,3 do
		for j = 1,3 do
			if self.board[i][j] == '_' then
				isFull = false
			end
		end
	end
	return isFull;
end

function Prototype.changePlayer(self)
	if self.currentPlayerMark == 'x' then
		self.currentPlayerMark = 'o'
	else
		self.currentPlayerMark = 'x';
	end
end

return Prototype

//Main Class located in ServerScriptService

local prototype = require(game.ServerStorage["TTT Class"])
local instance = prototype.new()

local function loopGame()
	repeat 
       
	       
		prototype.changePlayer(prototype)
	until prototype.checkForWin() or prototype.isFull()
end

loopGame()

I’m trying to create a loop that iterates over the two-player each turn, and the loop will return once there is a win or if the board is full. I’m stuck. I’m thinking of another solution where the client sends a remote event to the server when they click a box, the server checks if the player is the current player in turn, and then proceed to change the matrix representing the board accordingly, which in turn changes the TicTacToe Gui. The server then changes the current player in turn so the other player can play.

So in your game you could have two methods:

-- switch player method
function Prototype:SwitchPlayer()
  -- this will toggle x if current is o or vice versa
  self.currentPlayerMark = self.currentPlayerMark=='x' and 'o' or 'x'
end

-- place position
function Prototype:PlaceFigure(x,y)
  -- i will let you implement this one but basically
  -- place self.currentPlayerMark in postion x,y if empty
  -- then run self:SwitchPlayer() so the next turn uses the other player
end

You are going to need to use remotes anyway if you want this to work between multiple players. You should use a remote event to tell a player when their turn is and when their time is up, and then use a remote function to allow the player to make their move once the server tells them with the remote event that their turn has started. You’ll also need to validate the incoming data from the remote function and make sure that 1) it’s that player’s turn, and 2) that they are attempting to place in a valid index. Then if those conditions are both true, you can return true from the remote function which indicates to the client that they can render their piece being placed, and the server will tell the other client with the remote event where the first player moved and that the server is ready for the next client to play.

And regarding your loop, you should have another loop inside of your main loop after the switch player statement that checks if that player has finished their move, or if their move timed out.

I’m not entirely sure if you understand the purpose of using __index

What __index does is it means that it first searches the current table, then moves to the secondary condition. Which in this case is a table full of functions.

This effectively means you can do this

local instance = prototype.new();
instance:initializeBoard(); -- self is the first passed argument!
instance:checkRowsForWin(); 

for the loop game, you should change the player yield until the player makes a move.
Highly suggest using a remote function for this. Bindable Events and Functions | Roblox Creator Documentation

1 Like