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

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

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.

Related

aligning polygon around the edges

so ive tried to align polygons to achieve something like this:
but i get something like this:
local function signedArea(p, q, r)
local cross = (q.y - p.y) * (r.x - q.x)
- (q.x - p.x) * (r.y - q.y)
return cross
end
local function isCCW(p, q, r) return signedArea(p, q, r) < 0 end
local function jarvis_gift_wrapping_algorithm(points)
local numPoints = #points
if numPoints < 3 then return end
local leftMostPointIndex = 1
for i = 1, numPoints do
if points[i].x < points[leftMostPointIndex].x then
leftMostPointIndex = i
end
end
local p = leftMostPointIndex
local hull = {}
repeat
q = points[p + 1] and p + 1 or 1
for i = 1, numPoints, 1 do
if isCCW(points[p], points[i], points[q]) then q = i end
end
table.insert(hull, points[q])
p = q
until (p == leftMostPointIndex)
return hull
end
and its basically this: https://github.com/kennyledet/Algorithm-Implementations/blob/master/Convex_hull/Lua/Yonaba/convex_hull.lua
if anyone has any idea or know any algorithms that might help me to achieve that i would really appreciate that

Diamond-Square algorithm: How do I determine what tiles I need to run a diamond function and what tiles I need to run a square function on?

I'm working on a diamond-square heightmap generator and I've been stuck on a certain part for a while now.
I'm having trouble determining which tiles I need to run a square() function on and which tiles I need to run a diamond() function on.
I took a look at this guide: http://www.playfuljs.com/realistic-terrain-in-130-lines/ and I took their for loop they're using as an example, but it didn't seem to work at all.
The preferred language for the answer is Lua (or just kindly point me in the right direction). I just need someone to tell me what I need to do to get a for loop that works for both diamond and square functions.
-- height constraints
local min_height = 10
local max_height = 100
-- the grid
local K = 4
local M = 2^K -- the field is cyclic integer grid 0 <= x,y < M (x=M is the same point as x=0)
local heights = {} -- min_height <= heights[x][y] <= max_height
for x = 0, M-1 do
heights[x] = {}
end
-- set corners height (all 4 corners are the same point because of cyclic field)
heights[0][0] = (min_height + max_height) / 2
local delta_height = (max_height - min_height) * 0.264
local side = M
local sqrt2 = 2^0.5
repeat
local dbl_side = side
side = side/2
-- squares
for x = side, M, dbl_side do
for y = side, M, dbl_side do
local sum =
heights[(x-side)%M][(y-side)%M]
+ heights[(x-side)%M][(y+side)%M]
+ heights[(x+side)%M][(y-side)%M]
+ heights[(x+side)%M][(y+side)%M]
heights[x][y] = sum/4 + (2*math.random()-1) * delta_height
end
end
delta_height = delta_height / sqrt2
-- diamonds
for x = 0, M-1, side do
for y = (x+side) % dbl_side, M-1, dbl_side do
local sum =
heights[(x-side)%M][y]
+ heights[x][(y-side)%M]
+ heights[x][(y+side)%M]
+ heights[(x+side)%M][y]
heights[x][y] = sum/4 + (2*math.random()-1) * delta_height
end
end
delta_height = delta_height / sqrt2
until side == 1
-- draw field
for x = 0, M-1 do
local s = ''
for y = 0, M-1 do
s = s..' '..tostring(math.floor(heights[x][y]))
end
print(s)
end

Touch Lua's Draw Library Basics

WARNING: This question is only for Touch Lua users who have purchased and have knowledge of the Draw Library.
PLEASE REFER TO THE BOTTOM PORTION OF THIS QUESTION TO SEE THE FULL PROGRAM. THE SNIPPETS I USE IN THE BEGINNING ARE PART OF THAT PROGRAM (NUMPAD.LUA)
Okay, so now for the questions:
•What's the use of "." between "b" and "x"? Or "b" and "draw"? Etc...
•How does the table set up the button? Please be super specific?
•Why is there a "+", "*", and "(j-1)" in lines 7 and 8?
•What's height and width doing in there? I thought there were only x and y.
function createButtons()
buttons = { }
local c = 1
for i = 1, 4 do
for j = 1, 3 do
local b = { }
b.x = 80 + 60 * (j-1)
b.y = 160 + 60 * (i-1)
b.width = 40
b.height = 40
b.color = draw.blue
b.draw = drawButton
b.action = digitAction
buttons[c] = b
c = c + 1
end
end
buttons[1].title = '7'
buttons[2].title = '8'
buttons[3].title = '9'
buttons[4].title = '4'
buttons[5].title = '5'
buttons[6].title = '6'
buttons[7].title = '1'
buttons[8].title = '2'
buttons[9].title = '3'
buttons[10].title = '0'
buttons[11].title = '.'
buttons[11].action = dotAction
buttons[12].title = 'C'
buttons[12].color = draw.orange
buttons[12].action = clearAction
end
Lastly, referencing the program as a whole...
•How does the button know when you tap on it? Specifically what are the lines of code and how does it work? (I have a very faint understanding of track touches btw)
function digitAction(button)
if string.len(display.title) < 16 then
sys.alert('tock')
if display.started then
display.title = display.title .. button.title
else
if button.title ~= '0' then
display.title = button.title
display.started = true
end
end
else
sys.alert('tink')
end
end
function dotAction(button)
if string.find(display.title, '.', 1, true) then
sys.alert('tink')
else
display.title = display.title .. '.'
display.started = true
sys.alert('tock')
end
end
function clearAction(button)
sys.alert('tock')
display.title = '0'
display.started= false
end
function createDisplay()
display = { }
display.x = 60
display.y = 100
display.width = 200
display.height = 40
display.title = '0'
display.color = draw.red
display.started = false
end
function createButtons()
buttons = { }
local c = 1
for i = 1, 4 do
for j = 1, 3 do
local b = { }
b.x = 80 + 60 * (j-1)
b.y = 160 + 60 * (i-1)
b.width = 40
b.height = 40
b.color = draw.blue
b.draw = drawButton
b.action = digitAction
buttons[c] = b
c = c + 1
end
end
buttons[1].title = '7'
buttons[2].title = '8'
buttons[3].title = '9'
buttons[4].title = '4'
buttons[5].title = '5'
buttons[6].title = '6'
buttons[7].title = '1'
buttons[8].title = '2'
buttons[9].title = '3'
buttons[10].title = '0'
buttons[11].title = '.'
buttons[11].action = dotAction
buttons[12].title = 'C'
buttons[12].color = draw.orange
buttons[12].action = clearAction
end
function drawDisplay()
draw.setfont('Helvetica', 20)
draw.setlinestyle(2, 'butt')
local x1, y1 = display.x, display.y
local x2, y2 = x1 + display.width, y1 + display.height
draw.roundedrect(x1, y1, x2, y2, 10, display.color)
local w, h = draw.stringsize(display.title)
local x = x2 - 10 - w
local y = y1 + (display.height - h)/2
draw.string(display.title, x, y, draw.black)
end
function drawButton(b)
draw.setfont('Helvetica', 18)
draw.setlinestyle(2, 'butt')
local x1, y1 = b.x, b.y
local x2, y2 = x1+b.width, y1+b.height
draw.roundedrect(x1, y1, x2, y2, 10, 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)
end
function drawButtons()
for i = 1, #buttons do
buttons[i].draw(buttons[i])
end
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 drawScreen()
draw.beginframe()
draw.clear()
drawDisplay()
drawButtons()
draw.endframe()
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
function init()
draw.setscreen(1)
draw.settitle('Num Pad')
draw.clear()
draw.tracktouches (touchBegan, touchMoved, touchEnded)
createButtons()
createDisplay()
end
function mainloop()
while true do
draw.doevents()
drawScreen()
draw.sleep(30)
end
end
function main()
init()
mainloop()
end
-- start program
main()
Thank you so much for any help you can offer! I know this is a lot of questions, but this knowledge can really help propel me forward!
WARNING: This question is only for Touch Lua users who have purchased
and have knowledge of the Draw Library
Since when do you have to purchase something to answer programming questions? All your questions are on absolute Lua basics anyway.
What's the use of "." between "b" and "x"? Or "b" and "draw"? Etc...
The dot operator is used to index table members. So b.x will give you the value that belongs to key "x" in table b. Its syntactic sugar for b["x"].
How does the table set up the button? Please be super specific?
The function createButtons creates an empty table and fills it with buttons represented by a table b that stores various button properties.
Why is there a "+", "*", and "(j-1)" in lines 7 and 8?
Because the author of that program wants to add and multiply. Here the coordinates b.x and b.y are calculated. (j-1) is used because j starts at 1, but he needs it to start at 0 for this calculation.
The 2 for loops will create 4 rows of buttons, each containing 3 buttons as the x coordinate depends on parameter j while y depends on parameter i.
What's height and width doing in there? I thought there were only x
and y.
The button needs dimensions, not only a location. As b is created as a local variable within the for loop all its properties are set here. They may be changed later.
How does the button know when you tap on it? Specifically what are the
lines of code and how does it work?
Your mainloop will call draw.doevents() every cycle. So at some point there will be an event that will cause touchBegan to be called.
The button itself does not know that it was tapped. function touchBegan(x,y) will search if one of the buttons was hit at x,y by calling lookupButton(x,y) and call its action function. action is either one of dotAction, digitAction or clearAction. So if you tap on a digit button digitAction() will be called e.g.
Do yourself a favour and read a book on Lua or at least do a Lua tutorial. Befor diving into third party libraries. If you don't know how to index the most common Lua type or that + and * are arrithmetic operators, you will have a very hard time understanding code and you will not be productive in any way.
This program in particular uses tables to represent buttons, it does this to make it more manageable. The height and width are the same way. If you are new to the draw library, reviewing code like this is only going to confuse you. Most of your questions are actually about OOP honestly
Also this question probably isn't suitable for Stack Overflow right now. If you want help/a small tutorial on the subject feel free to PM me on the Touch Lua forum, my username is warspyking, but as it stands you need to either revise or delete this question.

Ported code having issues, can't figure out how this should work

Okay, so I ported this bit of code from a javascript file to Lua. It's a solution to the Bin Packing problem. Basically, this is a given a target rectangle size "init(x,y)", and then is given a table with blocks to fill said rectangle, "fit(blocks)". However when I run this I get the error "attempt to index local 'root' (a number value)". What is going wrong here?
I also don't fully understand how this code is working, someone helped me along with the porting process. When I pass a table "blocks" into the fit function, is it adding the attributes of block.fit.x and block.fit.y?
Any help is appreciated.
Edit: Fixed the error by changing "." to ":" when calling a method.
--ported from https://github.com/jakesgordon/bin-packing
local _M = {}
mt = {
init = function(t, x, y) --takes in dimensions of target rect.
t.root = { x = 0, y = 0, x = x, y = y }
end,
fit = function(t, blocks) --passes table "blocks"
local n, node, block
for k, block in pairs(blocks) do
if node == t.findNode(t.root, block.x, block.y) then
block.fit = t.splitNode(node, block.x, block.y)
end
end
end,
findNode = function(t, root, x, y)
if root.used then --if root.used then
return t.findNode(root.right, x, y) or t.findNode(root.down, x, y)
elseif (x <= root.x) and (y <= root.y) then
return root
else
return nil
end
end,
splitNode = function(t, node, x, y)
node.used = true
node.down = { x = node.x, y = node.y + y, x = node.x, y = node.y - y }
node.right = { x = node.x + x, y = node.y, x = node.x - x, y = y }
return node;
end,
}
setmetatable(_M, mt)
-- Let's do the object-like magic
mt.__index = function(t, k)
if nil ~= mt[k] then
return mt[k]
else
return t[k]
end
end
mt.__call = function(t, ...)
local new_instance = {}
setmetatable(new_instance, mt)
new_instance:init(...)
return new_instance
end
return _M
I don't know if this will help, but here is how I would have ported the code over to Lua.
local Packer = {}
Packer.__index = Packer
function Packer:findNode (root, w, h)
if root.used then
return self:findNode(root.right, w, h) or self:findNode(root.down, w, h)
elseif w <= root.w and h <= root.h then
return root
else
return nil
end
end
function Packer:fit (blocks)
local node
for _, block in pairs(blocks) do
node = self:findNode(self.root, block.w, block.h)
if node then
block.fit = self:splitNode(node, block.w, block.h)
end
end
end
function Packer.init (w, h)
local packer = {}
packer.root = {x = 0, y = 0, w = w, h = h}
return setmetatable(packer, Packer)
end
function Packer:splitNode (node, w, h)
node.used = true
node.down = {x = node.x, y = node.y + h, w = node.w, h = node.h - h}
node.right = {x = node.x + w, y = node.y, w = node.w - w, h = h }
return node
end
return Packer
Just place it in a file like packer.lua and import it into your main.lua with local Packer = require "packer"

Find close path or region using recursive method

I have a object in 2d array and i want to traverse through them top, left, right for that object acutally i want to check if there are making some loop or better making some closed region. See this picture for better explanation.
Acutally i have a X x Y of slot and when user touch on any of the region it adds the brick there so what i want to do is every time user add a brick check if it is making a close path.
I have writen recursive function for that but it's not working fine it always go for the top only and not right and left. Here is the code
function checkTrap(y,x)
if all_tiles[y][x].state == "changed" then --if brick is added at that location
last_move_y = y
last_move_x = x
--check for top
y = y - 1
if( y >= 1 and y <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to top at"..y..", "..x)
return checkTrap(y, x)
end
--check for bottom
y = y + 1
if( y >= 1 and y <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to bottom at"..y..", "..x)
return checkTrap(y, x)
end
--check for left
x = x - 1
if( x >= 1 and x <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to left at"..y..", "..x)
return checkTrap(y, x)
end
--check for right
x = x + 1
if( x >= 1 and x <= 6 and (last_move_y ~= y or last_move_x ~= x) ) then
print("Moved to right at"..y..", "..x)
return checkTrap(y, x)
end
elseif all_tiles[y][x] == object then
print("it's a loop"..y..", "..x)
return true;
else
print("not changed")
return false
end
end
Edit : New Solution
function findClosedRegion()
local currFlag, isClose = -1, false
local isVisited = {
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1}}
local k, m = 1, 1
while k <= 6 and not isClose
do
print("K "..k)
while m <= 6 and not isClose
do
print("M "..m)
if not isBrick[k][m] and isVisited[k][m] == -1 then
local cellsi = Stack:Create()
local cellsj = Stack:Create()
cellsi:push(k)
print("Pushed k "..k)
cellsj:push(m)
print("Pushed m "..m)
currFlag = currFlag + 1
isClose = true
while cellsi:getn() > 0 and isClose do
local p = cellsi:pop()
print("Pop p "..p)
local q = cellsj:pop()
print("Pop q "..q)
if( p >= 1 and p <= 6 and q >= 1 and q <= 6 ) then
if(not isBrick[p][q]) then
print("white ")
if(isVisited[p][q] == -1) then
print("invisited")
isVisited[p][q] = currFlag
cellsi.push(p - 1)
cellsj.push(q)
cellsi.push(p + 1)
cellsj.push(q)
cellsi.push(p)
cellsj.push(q + 1)
cellsi.push(p)
cellsj.push(q - 1)
cellsi:list()
else
if(isVisited[p][q] < currFlag) then
print("visited < currFlag")
isClose = false
end
end
end
else
isClose = false
end --p and q if ends here
end -- tile while end
else
--print("changed and not -1")
end
m = m + 1
end -- m while end
if(isClose) then
print("Closed path")
end
m = 1
k = k + 1
end -- k while end
end
The structure of the implementation does not recurse into other directions as only the first branch is called; somehow all neighbors should be included. Apparently you try to implement a kind of Deph-first search on your array. The approach seems absolutely rightm, but all neighbors of a cell have to be taken into account. What perhaps would help most would be to do a connected component analysis and fill all the connected components which touch the border.
EDITED:
Instead if searching with the help of black cells, we should search with white cells because your goal is to find area bound by black cells, even if diagonally adjacent. We should find a group of white cells which is only bordered by black cells and not by the border of the whole main grid. That should satisfy your purpose.
JS Fiddle: http://jsfiddle.net/4d4wqer2/
This is the revised algorithm I came up with:
for each cell and until closed area not found
if white and visitedValue = -1
push cell to stack
while stack has values and closed area not found
pop cell from stack
if invalid cell // Cell coordinates are invalid
this area is not closed, so break from the while
else
if white
if visitedValue = -1
{
mark visited
push neighboring four cells to the stack
}
else
if visitedValue > currVisitNumber // The current cells are part of previous searched cell group, which was not a closed group.
this area is not closed, so break from the while
if closed area found
show message
Programmed using JQuery:
function findArea() {
var currFlag = -1, isvisited = [], isClosed = false;
for (var k = 0; k < rows; k++) { // Initialize the isvisited array
isvisited[k] = [];
for (var m = 0; m < cols; m++)
isvisited[k][m] = -1;
}
for (var k = 0; k < rows && !isClosed; k++)
for (var m = 0; m < cols && !isClosed; m++) {
if (!isblack[k][m] && isvisited[k][m] == -1) { // Unvisited white cell
var cellsi = [k], cellsj = [m];
currFlag++;
isClosed = true;
while (cellsi.length > 0 && isClosed) { // Stack has cells and no closed area is found
var p = cellsi.pop(), q = cellsj.pop();
if (p >= 0 && p < rows && q >= 0 && q < cols) { // The cell coord.s are valid
if (!isblack[p][q])
if (isvisited[p][q] == -1) {
isvisited[p][q] = currFlag; // Mark visited
cellsi.push(p - 1); // Push the coord.s of the four adjacent cells
cellsj.push(q);
cellsi.push(p + 1);
cellsj.push(q);
cellsi.push(p);
cellsj.push(q + 1);
cellsi.push(p);
cellsj.push(q - 1);
}
else
if (isvisited[p][q] < currFlag) // The current group of white cells was part of a previous group of white cells which were found to be unbound by the black cells. So, skip this group.
isClosed = false;
}
else
isClosed = false; // The current cell is out of border. Hence skip the whole group.
}
}
}
if (isClosed)
alert('Closed area found');
}
JS Fiddle: http://jsfiddle.net/4d4wqer2/

Resources