Search code examples
randomluadrawtic-tac-toe

"Tic Tac Toe" Touch Lua random squares getting filled in?


So I recently purchased the draw library on Touch Lua! I've started trying to make a simple Tic Tac Toe game. I'm using a simple setup they used to detect clicks on the NumPad default program, so the buttons should work.

The problem is that when you tap a square, the O fills into seemingly-random squares, sometimes more than 1, up to 4+ squares may get filled.

I suspect the problem is the function Picked, which sets the title to X/O and then updates the board.

local Turn = nil
local Move = "O"
local Mode = nil

::ModePick::
print("1 player mode? (y/n)")
local plrs = io.read()
if plrs == "y" then
   Mode = 1
   goto TurnChoice
elseif plrs == "n" then
   Mode = 2
   goto Game
else
   goto ModePick
end

::TurnChoice::
 print("Would you like to go first? (Be O) (y/n)")
do
   local pick = io.read()
   if pick == "y" then
       Turn = 1
   elseif pick == "n" then
      Turn = 2
   else
      goto TurnChoice
   end
end

::Game::

local Buttons = {}

draw.setscreen(1)
draw.settitle("Tic Tac Toe")
draw.clear()
width, height = draw.getport()

function Picked(b)
   for i,v in pairs(Buttons) do
      if v == b then
         b.title = Move
         UpdateBoard()
      end
   end
   --Fill in X/O details
   --Detect if there's a tic/tac/toe
   --Set winning screen
   if Move == "O" then
       --Compute Move (1 player)
       --Move = "X" (2 player)
   else
      Move = "O"
   end
end

function DrawButton(b)
   draw.setfont('Helvetica', 50)
   draw.setlinestyle(2, 'butt')
   local x1, y1 = b.x, b.y
   local x2, y2 = x1+b.width, y1+b.height
   draw.rect(x1, y1, x2, y2, b.color)

   local w, h = draw.stringsize(b.title)
   local x = b.x + (b.width - w)/2
   local y = b.y + (b.height - h)/2
   draw.string(b.title, x, y, draw.black)
   return b
end

function Button(x, y, x2, y2, title, color, action)
   local action = action or function() end
   local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
   table.insert(Buttons, button)
   return button
end

function LookUpButton(x, y)
   for i = 1, #Buttons do
      local b = Buttons[i]
      if x > b.x and x < b.x+b.width and y > b.y and y < b.y+b.height then
         return b
      end
   end
   return nil
end

function TouchBegan(x, y)
   local b = LookUpButton(x, y)
   if b then
      b.action(b)
   end
end

function TouchMoved(x, y)
end

function TouchEnded(x, y)
end

draw.tracktouches(TouchBegan, TouchMoved, TouchEnded)


function CreateButton(x,y,x2,y2,txt,col,func)
   return DrawButton(Button(x, y, x2, y2, txt, col, func))
end

function UpdateBoard()
   draw.clear()
   for i = 1,3 do
        for ii = 1,3 do
             CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100,  Buttons[i + ii].title, draw.blue, Picked)
      end
   end
end

for i = 1,3 do
   for ii = 1,3 do
      CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100,  "", draw.blue, Picked)
   end
end

while true do
   draw.doevents()
   sleep(1)
end

Note: Sorry if the indention came out wrong, I pasted all this code in on my iPod, so I had to manually put in 4 spaces starting each line.

If anybody could help me out with this small setback I have, I'd love the help, if there's anything I'm missing I'd gladly edit it in just reply in the comments :D

EDIT: I've modified some of the code to fix how the table keeps getting new buttons, this is the code I have now, same problem, buttons are added in wrong place (and getting removed now):

function Button(x, y, x2, y2, title, color, action, prev)
   local action = action or function() end
   local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
   if prev then
      for i,v in pairs(Buttons) do
         if v == prev then
            table.remove(Buttons, i)
         end
      end
   end
   table.insert(Buttons, button)
   return button
end

function CreateButton(x,y,x2,y2,txt,col,func, prev)
   return DrawButton(Button(x, y, x2, y2, txt, col, func, prev))
end

function UpdateBoard()
   draw.clear()
   for i = 1,3 do
      for ii = 1,3 do
         CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100,  Buttons[i + ii].title, draw.blue, Picked, Buttons[i + ii])
      end
   end
end

EDIT: Thanks to Etan I've fixed UpdateBoard, squares are still random:

function UpdateBoard()
   draw.clear()
   local n = 1
   for i = 1,3 do
      for ii = 1,3 do
         CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100,  Buttons[n].title, draw.blue, Picked, Buttons[n])
         n = n + 1
      end
   end
end

Solution

  • It's been a while since I've got around to post the finished code, but this is what it looks like:

    function UpdateBoard(ended)
       local ended = ended or false
       local Act = nil
       if ended == true then
          Act = function() end
       else
          Act = Picked
       end
       draw.clear()
       local Buttons2 = {}
       for i,v in pairs(Buttons) do
          Buttons2[i] = v
       end
       Buttons = {}
       local n = 1
       for i = 1,3 do
          for ii = 1,3 do
             CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100,  Buttons2[n].title, draw.blue, Act, Buttons2[n], i, ii)
             n = n + 1
          end
       end
       OpenButtons = {}
       ClosedButtons = {}
       for i,v in pairs(Buttons) do
          if v.title == "" then
             table.insert(OpenButtons, v)
          else
             table.insert(ClosedButtons, v)
          end
       end
    end
    

    It may seem a bit complicated for the question, but this is the code after multiple other things.

    The main difference you should note here, is that it's recreating the table of buttons, so it does not recount new buttons, and it uses n to count up, instead of using i and ii.