Lua Love2d Quadtree recursion - recursion

UPDATE -- I figured it out. Turns out I am bad at math and visualizing 2d points. I wasn't setting south or east subdivisions correctly.
I have been trying to make a quadtree to track points in Love2d. I have the most of the code written, but I don't think the recursion is working properly.
I'm pretty new to the coding scene, so I really don't know where to start.
It seems to leave out points that go into the southeast quadrant.
I think as it goes recursively into the insert function it either looks at the parents point array or doesn't seem to go into all the insert functions.
local QuadTree = {}
QuadTree.__index = QuadTree
function QuadTree:new(boundary,capacity)
local quadTemp = {}
setmetatable(quadTemp, QuadTree)
if (not boundary) then
print('No boundary given to new QuadTree')
end
if (type(capacity) ~= 'number') then
print('Boundary should be a number')
end
if (capacity < 1) then
print('capacity should be greater than one')
end
quadTemp.boundary = boundary
quadTemp.capacity = capacity
quadTemp.points = {}
quadTemp.hasDivided = false
return quadTemp
end
function QuadTree:insert(p)
--If this point doesnt belong in this spot dont add it
if (not self.boundary:contains(p)) then
return false
elseif (#self.points<self.capacity) then
table.insert(self.points,p)
return true
elseif(not self.hasDivided) then
self:subdivide()
elseif(self.hasDivided) then
return self.northeast:insert(p) or
self.northwest:insert(p) or
self.southeast:insert(p) or
self.southwest:insert(p)
end
end
function QuadTree:subdivide()
local x = self.boundary.xpos
local y = self.boundary.ypos
local w = self.boundary.width / 2
local h = self.boundary.height / 2
local nw = Rectangle:new(x,y,w,h)
self.northwest = QuadTree:new(nw,self.capacity)
local ne = Rectangle:new(w,y,w,h)
self.northeast = QuadTree:new(ne,self.capacity)
local sw = Rectangle:new(x,h,w,h)
self.southwest = QuadTree:new(sw,self.capacity)
local se = Rectangle:new(w,h,w,h)
self.southeast = QuadTree:new(se,self.capacity)
self.hasDivided = true
end
function QuadTree:query(range,found)
--If we havent found any yet lets create a list incase we do
if (not found) then found = {} end
--If this cell doesnt contain the boundary then return an empty list
if (not range:intersects(self.boundary)) then
return found
end
for k,v in pairs(self.points) do
if (range:contains(v)) then
table.insert(found,v)
end
end
--If the current cell has divided we need to check its children
if (self.hasDivided) then
self.northwest:query(range,found)
self.northeast:query(range,found)
self.southwest:query(range,found)
self.southeast:query(range,found)
end
return found;
end

Related

How to redefine values in inner tables?

Basically, scan the entire table for values of type say booleans for example and change them into a string, must work for inner tables and dictionaries...
local Table = {
String = "abc",
Number = 123,
Boolean = true,
InnerTable = {
Boolean2 = false,
InnerInnerTable = {
Boolean3 = true,
InnerInnerInnerTable = {
-- And so on...
}
}
}
}
In this example I want to change every boolean in the table to a string like "true" but without knowing what the table looks like, what I need is a function for any table parsed to be edited (dictionary or not). I couldn't accomplish this with a for loop or custom recursive functions so I need help.
What you need is a simple traversal of the table structure which maps booleans to strings. This can be implemented recursively as follows:
local function deep_bool_to_string(tab)
for k, v in pairs(tab) do
if type(v) == "boolean" then
tab[k] = tostring(v)
elseif type(v) == "table" then
deep_bool_to_string(v)
end
end
end
Usage in your example: deep_bool_to_string(Table). Mutates Table.
Note that this only recursively dives into values, not keys of tables, as the latter isn't well defined: Should {["true"] = 1, [true] = 2} become {["true"] = 1} or {["true"] = 2}?
In its current form, this function has two limitations:
A circular table structure will cause it to overflow the stack.
A too deeply nested table structure may do the same.
(1) can be fixed by keeping track of already converted tables:
local deep_bool_to_string = function(tab)
local seen = {} -- "Set" of seen tables
local function convert(t)
seen[t] = true
for k, v in pairs(t) do
if type(v) == "boolean" then
t[k] = tostring(v)
elseif type(v) == "table" and not seen[v] then
convert(v)
end
end
end
convert(tab)
end
(2) can be fixed by implementing the traversal using a table-based "stack":
local deep_bool_to_string = function(tab)
local seen = {[tab] = true} -- "Set" of seen tables
local to_convert = {tab} -- "Stack" of tables to convert
repeat
local t = table.remove(to_convert) -- "pop" from stack
for k, v in pairs(t) do
if type(v) == "boolean" then
t[k] = tostring(v)
elseif type(v) == "table" and not seen[v] then -- new table found?
seen[v] = true
table.insert(to_convert, v) -- "push" on stack
end
end
until #to_convert == 0
end
All these are implementations of depth-first traversals, since they are usually more convenient to write (and more efficient) than breath-first traversals since they use a stack rather than a queue.

Handle previous state in continuous rotation

Hello i have the following lua code which functionality is to rotate a point creating a circle. The problem I'm having is with initial and/or last state. Since there is a clock running whenever i stop the rotation and start again, the point jumps around. I tried saving the last value after the lfo is turned off, and then use this value in each sin and cos functions but i cannot make it work well.
Thank you!
The Code:
local last = 0
local trigger = false
function update()
t = getMillis()
T = 3000
if trigger == true then
x = math.cos(2*math.pi*( (t - last) + t) /T)
y = math.sin(2*math.pi*( (t - last) + t) /T)
end
end
function onValueChanged(key)
if key == "x" and self.values.x == 1 then
if trigger == true then
last = t
end
trigger = not trigger
end
end

Function only works when there is a println() statement at the end of each iteration

I'm trying to implement a 3-clique (triangle) finding algorithm from a paper (p. 212-213) in Julia, but I'm running into a problem with the code
function find_triangle(graph::AdjacencyListGraphs)
new_graph = deepcopy(graph)
sort!(new_graph.edges, by=x->new_graph.D[x], rev=true)
cliques = Vector{Vector{Int64}}()
marked_nodes = Set()
for i in 1:new_graph.n - 2
cur = new_graph.edges[new_graph.edges.keys[1]]
# mark vertices adjacent to i
for j in 1:length(cur)
push!(marked_nodes,cur[j])
end
# search in marked nodes
for j in 1:length(cur)
u = cur[j]
for w in new_graph.edges[u]
if w in marked_nodes
cur_clique = [new_graph.edges.keys[1], u, w]
push!(cliques, cur_clique)
end
delete!(marked_nodes, u)
end
end
# delete node
for key in new_graph.edges.keys
filter!(x->x≠new_graph.edges.keys[1],new_graph.edges[key])
end
delete!(new_graph.edges, new_graph.edges.keys[1])
# this println() call is currently used to prevent an unknown error. Not sure why, but this fixes it
println(new_graph)
end
return cliques
end
The input to the function is the following
nodes = [1,2,3,4,5,6]
edges = OrderedDict{Int64, Vector{Int64}}()
edges[1] = [2,3,5]
edges[2] = [1,3,4,6]
edges[3] = [1,2,4,6]
edges[4] = [2,3,5,6]
edges[5] = [1,4]
edges[6] = [2,3,4]
degrees = [3,4,4,4,2,3]
graph = AdjacencyListGraphs(nodes, 6, 10, degrees, edges)
cliques = find_triangle(graph)
And the type definition for the graph is as follows:
mutable struct AdjacencyListGraphs{Int64}
vals::Vector{Int64} # vertex list
n::Int64 # number of vertices
m::Int64 # number of edges
D::Vector{Int64} # degree sequence
edges::OrderedDict{Int64, Vector{Int64}} # adjacency list
end
The function runs properly if I include the println() statement, but if I remove just that statement, I run into the following bug
ERROR: LoadError: KeyError: key 2 not found
The issue to me looks like an error in the deletion of a node, and someohow the println() statement fixes it. The reason why I need to fix this is because I'm trying to run the code on a much bigger graph with about a million triangles, but the println() call at each step is literally crashing my computer.
Any help would be greatly appreciated; thank you!
The reason of the problem is that you use keys field of OrderedDict which is private. You should use accessor function e.g. like this:
function find_triangle(graph::AdjacencyListGraphs)
new_graph = deepcopy(graph)
sort!(new_graph.edges, by=x->new_graph.D[x], rev=true)
cliques = Vector{Vector{Int64}}()
marked_nodes = Set()
for i in 1:new_graph.n - 2
curk = first(keys(new_graph.edges))
cur = new_graph.edges[curk]
# mark vertices adjacent to i
for j in 1:length(cur)
push!(marked_nodes,cur[j])
end
# search in marked nodes
for j in 1:length(cur)
u = cur[j]
for w in new_graph.edges[u]
if w in marked_nodes
cur_clique = [curk, u, w]
push!(cliques, cur_clique)
end
delete!(marked_nodes, u)
end
end
# delete node
for key in new_graph.edges.keys
filter!(x->x≠curk,new_graph.edges[key])
end
delete!(new_graph.edges, curk)
# this println() call is currently used to prevent an unknown error. Not sure why, but this fixes it
# println(new_graph)
end
return cliques
end
The reason for the problem is that you delete keys in the dictionary, but not call rehash! on it. Incidentally rehash! is called when you call println because it calls iterate which in turn calls rehash!. So this would work:
function find_triangle(graph::AdjacencyListGraphs)
new_graph = deepcopy(graph)
sort!(new_graph.edges, by=x->new_graph.D[x], rev=true)
cliques = Vector{Vector{Int64}}()
marked_nodes = Set()
for i in 1:new_graph.n - 2
DataStructures.OrderedCollections.rehash!(new_graph.edges)
cur = new_graph.edges[new_graph.edges.keys[1]]
# mark vertices adjacent to i
for j in 1:length(cur)
push!(marked_nodes,cur[j])
end
# search in marked nodes
for j in 1:length(cur)
u = cur[j]
for w in new_graph.edges[u]
if w in marked_nodes
cur_clique = [new_graph.edges.keys[1], u, w]
push!(cliques, cur_clique)
end
delete!(marked_nodes, u)
end
end
# delete node
for key in new_graph.edges.keys
filter!(x->x≠new_graph.edges.keys[1],new_graph.edges[key])
end
delete!(new_graph.edges, new_graph.edges.keys[1])
# this println() call is currently used to prevent an unknown error. Not sure why, but this fixes it
#println(new_graph)
end
return cliques
end
but you should not write code like this, but rather use public API.
Maybe some body overwrote println or show for that custom type AdjacencyListGraphs, is the only reason I cuold find for a println to change the state of the code!.

Searching in database with scrambled words in SQLite

I am wondering if its possible to search in the database with the given scrambled words.
I have a mobs table in database and it holds the name of the monster names
If given monster name is A Golden Dregon or A Golden Dfigon or A Gelden Dragon I want it to find A Golden Dragon or with the matches that close to it from database. Usually one or two letters at max is given like this as scrambled.
Is that possible with just SQL queries? Or should I build the query by parsing the given monster name?
I am using LUA for the code side.
I have come to know this search type as a fuzzy search. I mainly program in JS and use fuse.js all the time for this kind of problem.
Fuzzy Searches are based on the Levenshtein algorithm that rate the distance of two strings. When you have this distance value you can sort or drop elements from a list based on the score.
I found the algorithm in lua here.
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
As explained in the site you compare two strings like so and get a score based on the distance of them, then sort or drop the items being search based on the scores given. As this is CPU expensive I would suggest caching or use a memoize function to store common mistakes.
levenshtein('referrer', 'referrer') -- zero distance
>>> 0
levenshtein('referrer', 'referer') -- distance of one character
>>> 1
levenshtein('random', 'strings') -- random big distance
>>> 6
Got a simple version of it working in lua here I must say lua is an easy language to pick up and start coding with.
local monsters = {'A Golden Dragon', 'Goblins', 'Bunny', 'Dragoon'}
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
--Fuzzy Search Returns the Best Match in a list
function fuzzySearch(list, searchText)
local bestMatch = nil;
local lowestScore = nil;
for i = 1, #list do
local score = levenshtein(list[i], searchText)
if lowestScore == nil or score < lowestScore then
bestMatch = list[i]
lowestScore = score
end
end
return bestMatch
end
print ( fuzzySearch(monsters, 'golen dragggon') )
print ( fuzzySearch(monsters, 'A Golden Dfigon') )
print ( fuzzySearch(monsters, 'A Gelden Dragon') )
print ( fuzzySearch(monsters, 'Dragooon') ) --should be Dragoon
print ( fuzzySearch(monsters, 'Funny') ) --should be Bunny
print ( fuzzySearch(monsters, 'Gob') ) --should be Goblins
Output
A Golden Dragon
A Golden Dragon
A Golden Dragon
Dragoon
Bunny
Goblins
For SQL
You can try to do this same algorithm in T-SQL as talked about here.
In SQLlite there is an extension called editdist3 which also uses this algorithm the docs are here.
I would be hard to compensate for all the different one and two letter scrambled combinations, but you could create a lua table of common misspellings of "A Golden Dragon" check if it is in the table. I have never used lua before but here is my best try at some sample code:
local mob_name = "A Golden Dregon"--you could do something like, input("Enter mob name:")
local scrambled_dragon_names = {"A Golden Dregon", "A Golden Dfigon", "A Gelden Dragon"}
for _,v in pairs(scrambled_dragon_names) do
if v == mob_name then
mob_name = "A Golden Dragon"
break
end
end
I really hope I have helped!
P.S. If you have anymore questions go ahead and comment and I will try to answer ASAP.
You will have to parse the given monster name to some extent, by making assumptions about how badly it is misspelled. For example, if the user supplied the name
b fulden gorgon
There is no way in hell you can get to "A Golden Dragon". However, if you assume that the user will always get the first and last letters of every word correctly, then you could parse the words in the given name to get the first and last letters of each word, which would give you
"A", "G" "n", "D" "n"
Then you could use the LIKE operator in your query, like so:
SELECT * FROM mobs WHERE monster_name LIKE 'A G%n D%n';
The main point here is what assumptions you make about the misspelling. The closer you can narrow it down, the better your query results will be.

Assistance with Lua Cosine, wrong results returned

Ok, first up, this is NOT for a class, test, or other student type activity.
I'm a scripter for a game, and am trying to implement the math library for all to use, and unfortunately, all I have available to me is very basic lua. The implemented version cannot be changed, and does not include any libraries. For those wondering, its for scripting in Fold.It.
Here's what I have...
math={}
math.fact = function(b) if(b==1)or(b==0) then return 1 end e=1 for c=b,1,-1 do e=e*c end return e end
math.pow = function(b,p) e=b if(p==0) then return 1 end if(p<0) then p=p*(-1) end for c=p,2,-1 do e=e*b end return e end
math.cos = function(b,p) e=0 p=p or 10 for i=1,p do e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i)) end return e end
To clarify above, math.fact returns factorial, which is returning accurate to about 10 points of precision, and is a new function I've done to aid in cosine calculation.
The math.pow is also a new function to handle returning powers, also working as expected.
The issue is with the cosine function. Its returning unexpected values. Here's an easier to digest version (I've been writing my library stuff ultra lean)...
function math.cos(value,precision)
result=0
precision=precision or 10
for i=1,precision do
result=result+(math.pow(-1,i)*math.pow(value,2*i)/math.fact(2*i))
end
return e
end
The problem is, with those functions, for print(math.cos(90)) it returns 4.77135... when I'm expecting -0.44807... (based on calc in scientific mode, or using an online tool to cos(90)).
I'm also having issues with sin and tan, however they are similarly written to cos, which seems to have been done in many languages. If I can figure out what I'm doing wrong, I can get them all fixed.
EDIT: Corrected typo
First, your lua doesn't run. Second, you need to make your variables local. Third, cosine starts with a one.
The problem is because the Taylor series you are using only converges on the correct values of cosine close to zero. You would have to use a far more terms of the series to get it to handle 90 correctly. You can fix this for your implementation two ways:
Add a pi constant. Then use a while loop to adjust the value such that abs(value) < 2*pi:
math.pi = 3.14159265358
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
Or - find or implement a version of fmod in lua.
Here is the corrected code (you can minify it):
math={}
math.fact = function(b)
if(b==1)or(b==0) then
return 1
end
local e=1
for c=b,1,-1 do
e=e*c
end
return e
end
math.pow = function(b,p)
local e=b
if(p==0) then
return 1
end
if(p<0) then
p=p*(-1)
end
for c=p,2,-1 do
e=e*b
end
return e
end
math.cos = function(b,p)
local e=1
b = math.correctRadians(b)
p=p or 10
for i=1,p do
e=e+(math.pow(-1,i)*math.pow(b,2*i)/math.fact(2*i))
end
return e
end
math.pi = 3.1415926545358
math.correctRadians = function( value )
while value > math.pi*2 do
value = value - math.pi * 2
end
while value < -math.pi*2 do
value = value + math.pi * 2
end
return value
end
interactive lua run:
imac:~ root$ lua -i temp.lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print( math.cos( 90 ) )
-0.44807359244883
>

Resources