When returning a table get {} - oop

I am trying to create a maze generation script using the module listed below. I'm having this strange problem were the grid variable has a value, but when return grid is called, it returns and empty table? Here is the code to the module script.
local ServerStorage = game:GetService("ServerStorage")
local cellTemplate = ServerStorage:WaitForChild("Cell")
local Maze = {}
local cellObject = {}
local grid = {}
Maze.Size = 25
Maze.CellWidth = 9
Maze.CellLength = 9
Maze.Offset = Vector3.new(0,0,0)
function Maze.new(x,z) -- Create a new cell
local newCell = {}
setmetatable(newCell,{ -- Allows us to create functions for a cell easier
__index = cellObject
})
newCell.X = math.clamp(x,1,Maze.Size)
newCell.Z = math.clamp(z,1,Maze.Size)
newCell.Visited = false
newCell.Model = cellTemplate:Clone()
newCell.Base = newCell.Model:WaitForChild("Base")
newCell.Model.Name = newCell.Model.Name.. "_".. newCell.X.. "-".. newCell.Z
newCell.Walls = {
["Forward"] = newCell.Model:WaitForChild("Forward");
["Backward"] = newCell.Model:WaitForChild("Backward");
["Left"] = newCell.Model:WaitForChild("Left");
["Right"] = newCell.Model:WaitForChild("Right");
}
if not grid[x] then grid[x] = {} end -- We might not have anything on that x axis yet; inserts it into the table
grid[x][z] = newCell
print(grid)
return newCell
end
function Maze.RenderAll() -- Render every cell; exists for more readibility
for _,cellRow in pairs(grid) do -- Loop through every cell row
for _,cell in pairs(cellRow) do -- Loop through every cell in the row
cell:Render() -- Render the cell
end
end
end
function Maze.Grid() -- Allows other scripts to get the grid but not modify it
return grid
end
function Maze.FilterUnvisited(cells) -- Takes in a table and returns one with only the cells in the table that are unvisited
local unvisited = {}
for _,cell in pairs(cells) do -- Loop through every cell in the table passed
if not cell.Visitied then -- The cell hasn't been visited
table.insert(unvisited,cell)
end
end
return unvisited
end
function Maze.GetCell(x,z)
local cell
if grid[x] and grid[x][z] then
cell = grid[x][z]
else
cell = nil
end
return cell
end
function cellObject:Render() -- Render the cell
self.Model:SetPrimaryPartCFrame(CFrame.new(Vector3.new(self.X * Maze.CellLength,0,self.Z * Maze.CellWidth) + Maze.Offset)) -- Move the cell to the correct position
if self.Visited then -- We have gone through the cell
self.Model.PrimaryPart.Color3 = Color3.new(0,1,0) -- Show that the cell has been visited; used for debugging
end
self.Model.Parent = workspace
end
function cellObject:Neighbours() -- Returns the cell's neigbours
local neighbours = {}
-- Order: Right Left Up Down
if grid[self.X + 1] and grid[self.X + 1][self.Z] then -- A cell with +1 X exists
table.insert(neighbours,grid[self.X + 1][self.Z])
end
if grid[self.X - 1] and grid[self.X - 1][self.Z] then -- A cell with -1 X exists
table.insert(neighbours,grid[self.X - 1][self.Z])
end
if grid[self.X][self.Z + 1] then -- A cell with +1 Z exists
table.insert(neighbours,grid[self.X][self.Z + 1])
end
if grid[self.X][self.Z - 1] then -- A cell with -1 Z exists
table.insert(neighbours,grid[self.X][self.Z - 1])
end
return neighbours
end
function cellObject:RandomNeighbour()
local neighbours = self:Neighbours() -- Gets the neigbours of the current cell
if #neighbours > 0 then
return neighbours[math.random(1,#neighbours)] -- Returns a random neigbour
else
return nil
end
end
function cellObject:WallArray() -- Returns an array of the walls instead of a table
local wallArray = {}
wallArray[1] = self.Walls.Forward
wallArray[2] = self.Walls.Right
wallArray[3] = self.Walls.Left
wallArray[4] = self.Walls.Backward
return wallArray
end
function cellObject:Join(cell) -- Joins 2 cells together
local wallPosition = self.Base.Position:Lerp(cell.Base.Position,.5) -- This will return the position of the wall (excluding the Y)
local cell1Array = self:WallArray()
local cell2Array = cell:WallArray()
for wallIndex,wall in pairs(cell1Array) do
if wall.Position.X == wallPosition.X and wall.Position.Z == wallPosition.Z then -- Its the right wall
wall.Transparency = 1
wall.CanCollide = false
cell2Array[4 - (wallIndex - 1)].Transparency = 1
cell2Array[4 - (wallIndex - 1)].CanCollide = false
break -- We don't need to loop anymore, since we've already removed the walls
end
end
end
function cellObject:Unjoin(cell) -- Unjoins 2 cells
local wallPosition = self.Base.Position:Lerp(cell.Base.Position,.5) -- This will return the position of the wall (excluding the Y)
local cell1Array = self:WallArray()
local cell2Array = cell:WallArray()
for wallIndex,wall in pairs(cell1Array) do
if wall.Position.X == wallPosition.X and wall.Position.Z == wallPosition.Z then -- Its the right wall
wall.Transparency = 0
wall.CanCollide = true
cell2Array[4 - (wallIndex - 1)].Transparency = 0
cell2Array[4 - (wallIndex - 1)].CanCollide = true
break -- We don't need to loop anymore, since we've already added the walls
end
end
end
return Maze
Below is the piece of code I'm having diffuculty with.
function Maze.Grid() -- Allows other scripts to get the grid but not modify it
return grid
end
I have tested printing the grid variable and it's not {} but when I call the function in the script below, I always get {}! I have no idea why this is.
Is this a bug in roblox or am I being stupid?
local ServerScriptService = game:GetService("ServerScriptService")
local Maze = require(ServerScriptService:WaitForChild("Maze"))
local latestX = 0
local latestZ = 0
function CreatePath(cell)
local nextCell = cell:RandomNextCell(false)
if nextCell then -- We have a cell next to the current one
print("Joining cells:",cell,nextCell)
cell:Join(nextCell)
cell.Visited = true
cell:Render()
wait(.01)
CreatePath(nextCell)
else -- It must be the end of the maze
print("Path generated!")
print("Maze end: ".. cell.Model.Name)
cell.Base.Color = Color3.new(1,0,0)
end
end
function GenerateMaze()
local cell = Maze.new(latestX + 1,latestZ + 1) -- Create a new cell
cell:Render() -- Render it
print("Created cell")
latestZ += 1
if latestZ > Maze.Size then -- It has exceeded the max size, move on to a new row
latestX += 1
latestZ = 0
end
if #Maze.Grid() < Maze.Size ^ 2 then
wait(.01)
GenerateMaze()
else
print("Grid completed, generating path...")
CreatePath(Maze.GetCell(1,1))
end
end
GenerateMaze()

You are returning a cached value, or well i don't find out other reason.
You may do (and it's not editable):
function Maze.Grid(i, l)
local passed = 1
local response = {}
for index, v in pairs(grid) do
response[index] = i and passed >= i and l and passed <= l and v or not (i or l) and v
-- basically get more than `i` if it, and minor than `l` if it passed
i = i + 1
end
return response
end
It should work, I don't tested it sorry.

Related

Solving 15Puzzle with Julia

I'm trying to use Julia to solve the common tile game 15 Puzzle using Julia using A* algorithm. I am quite new to the language and my style may seem very C like. When I try the following code, I run out of memory. I'm not sure if its related to the use of a pointer style in my structs or just bad design.
struct Node
parent
f::Int64
board::Array{Int64,1}
end
function findblank(A::Array{Int64,1})
x = size(A,1)
for i = 1:x
if A[i] == x
return i
end
end
return -1
end
function up(A::Array{Int64,1})
N = size(A,1)
Nsq = isqrt(N)
blank = findblank(A)
B = copy(A)
if blank / Nsq <= 1
return nothing
end
B[blank-Nsq],B[blank] = B[blank],B[blank-Nsq]
return B
end
function down(A::Array{Int64,1})
N = size(A,1)
Nsq = isqrt(N)
blank = findblank(A)
B = copy(A)
if (blank / Nsq) > (Nsq -1)
return nothing
end
B[blank+Nsq],B[blank] = B[blank],B[blank+Nsq]
return B
end
function left(A::Array{Int64,1})
N = size(A,1)
Nsq = isqrt(N)
blank = findblank(A)
B = copy(A)
if (blank % Nsq) == 1
return nothing
end
B[blank-1],B[blank] = B[blank],B[blank-1]
return B
end
function right(A::Array{Int64,1})
N = size(A,1)
Nsq = isqrt(N)
blank = findblank(A)
B = copy(A)
if (blank % Nsq) == 0
return nothing
end
B[blank+1],B[blank] = B[blank],B[blank+1]
return B
end
function manhattan(A::Array{Int64,1})
N = size(A,1)
Nsq = isqrt(N)
r = 0
for i in 1:N
if (A[i]==i || A[i]==N)
continue
end
row1 = floor((A[i]-1) / Nsq)
col1 = (A[i]-1) % Nsq
row2 = floor((i-1) / Nsq)
col2 = (i-1) % Nsq
r+= abs(row1 - row2) + abs(col1 - col2)
end
return r
end
# start = [1,2,3,4,5,6,7,9,8]
# start = [6,5,4,1,7,3,9,8,2] #26 moves
start = [7,8,4,11,12,14,10,15,16,5,3,13,2,1,9,6] # 50 moves
goal = [x for x in 1:length(start)]
# println("The manhattan distance of $start is $(manhattan(start))")
g = 0
f = g + manhattan(start)
pq = PriorityQueue()
actions = [up,down,left,right]
dd = Dict{Array{Int64,1},Int64}()
snode = Node(C_NULL,f,start)
enqueue!(pq,snode,f)
pos_seen = 0
moves = 0
while (!isempty(pq))
current = dequeue!(pq)
if haskey(dd,current.board)
continue
else
push!(dd, current.board =>current.f)
end
if (current.board == goal)
while(current.board != start)
println(current.board)
global moves +=1
current = current.parent[]
end
println(start)
println("$start solved in $moves moves after looking at $pos_seen positions")
break
end
global pos_seen+=1
global g+=1
for i in 1:4
nextmove = actions[i](current.board)
if (nextmove === nothing || nextmove == current.board || haskey(dd,nextmove))
continue
else
global f = g+manhattan(nextmove)
n = Node(Ref(current),f,nextmove)
enqueue!(pq,n,f)
end
end
end
println("END")

Why doesn't this method get called?

I'm talking about MovingGround:update(). It doesn't crash; It just doesn't do anything that's in the method.
I did other things in the method. I set the player pos to 100 100 but that didn't happen so there's (probably) no error in the method itself—at least not that makes it do nothing. The method just doesnt get called!! I think the question is pretty much says the rest! Sooooo.... Here's the code!
-- Grounds
Ground = {}
Ground.__index = Ground
function Ground:new(x,y,width,height)
grd = {}
setmetatable(grd, Ground)
grd.x = x
grd.y = y
grd.w = width
grd.h = height
grd.moving = false
return grd
end
function Ground:draw(r,g,b)
love.graphics.setColor(r,g,b)
love.graphics.rectangle("line",self.x,self.y,self.w,self.h)
end
function Ground:update()
end
MovingGround = {}
MovingGround.__index = MovingGround
function MovingGround:new(x,y,w,h,spdx,spdy,stepsx,stepsy)
grd = {}
setmetatable(grd, Ground)
grd.x = x
grd.y = y
grd.w = w
grd.h = h
grd.moving = true
grd.spdx = spdx
grd.spdy = spdy
grd.stepsxmax = stepsx
grd.stepsymax = stepsy
grd.stepsx = 0
grd.stepsy = 0
grd.xdir = 1
grd.ydir = 1
return grd
end
function MovingGround:draw(r,g,b)
love.graphics.setColor(r,g,b)
love.graphics.rectangle("line",self.x,self.y,self.w,self.h)
love.graphics.rectangle("fill",300,self.y,self.w,self.h)
end
function MovingGround:update()
if self.stepsx > self.stepsxmax or self.stepsx < 0 then self.spdx = -self.spdx self.dirx = -self.dirx end
if self.stepsy > self.stepsymax or self.stepsy < 0 then self.spdy = -self.spdy self.diry = -self.diry end
self.x = self.x + self.spdx
self.y = self.y + self.spdy
self.stepsx = self.stepsx + self.dirx
self.stepsy = self.stepsy + self.diry
end
-- Main
require"functions"
require"player"
require"grounds"
grounds= {}
width = love.graphics.getWidth()
height = love.graphics.getHeight()
function love.load()
test = Player:new(100,100,"w","a","s","d")
grounds[5] = Ground:new(2,2,25,595) --links
grounds[2] = Ground:new(2,2,795,25) --oben
grounds[3] = Ground:new(772,2,25,595) --rechts
grounds[4] = Ground:new(2,572,795,25) --unten
grounds[1] = MovingGround:new(50,400,100,20,0,3,0,15)
end
function love.draw()
test:draw(255,0,255)
love.graphics.print("y : " .. tostring(test.y),10,10)
love.graphics.print("x : " .. tostring(test.x),10,30)
love.graphics.print(test.spdy,10,60)
love.graphics.print(gd,10,90)
love.graphics.print(1000 / gd,10,150)
love.graphics.print(booltoString(test.onGround),10,120)
love.graphics.print(grounds[1].stepsy,10,210)
for i,v in ipairs(grounds) do
grounds[i]:draw(255,255,255)
end
end
function love.update(d)
gd = d
test:update(d)
for i,v in ipairs(grounds) do
grounds[i]:update()
end
end
function love.keypressed(key,code)
if key == "space" then test:jump(-700) end
end
I really recommend using a debugger to determine the cause of this issue. Here's a walkthrough:
Find a place where the update method is being called on a MovingGround object and set a breakpoint there.
Run your program with debugging enabled, until it reaches the breakpoint.
Step into the call to the update method. What method do you end up getting taken to? Is it the method you were expecting?
Now that you're inside of the update method, look at the metatable of self. Is the metatable MovingGround?
The metatable was set inside of MovingGround:new, so set a breakpoint at the beginning of MovingGround:new and restart the program. Run until it reaches the breakpoint.
Step forward (using "step over", not "step into") until you see that the metatable of grd has been set as you saw in step 4.
Look at the line that you just stepped over. What needs to be changed?
Spoiler: in MovingGround:new, the metatable is getting set to Ground instead of MovingGround.
You are supposed to pass in dt into any update function.
In this case, the function should be MovingGround:update(dt) (ground.lua) so that it updates every frame.
Similarly, in main.lua update function, the call should be grounds[i]:update(dt).

How to Plot a function of two variables in Julia with pyplot

I'm trying to plot a function of two variables with pyplot in Julia. The working starting-point is the following (found here at StackOverflow):
function f(z,t)
return z*t
end
z = linspace(0,5,11)
t = linspace(0,40,4)
for tval in t
plot(z, f(z, tval))
end
show()
This works right for me and is giving me exactly what I wanted:
a field of lines.
My own functions are as follows:
## needed functions ##
const gamma_0 = 6
const Ksch = 1.2
const Kver = 1.5
function Kvc(vc)
if vc <= 0
return 0
elseif vc < 20
return (100/vc)^0.1
elseif vc < 100
return 2.023/(vc^0.153)
elseif vc == 100
return 1
elseif vc > 100
return 1.380/(vc^0.07)
else
return 0
end
end
function Kgamma(gamma_t)
return 1-((gamma_t-gamma_0)/100)
end
function K(gamma_t, vc)
return Kvc(vc)*Kgamma(gamma_t)*Ksch*Kver
end
I've tried to plot them as follows:
i = linspace(0,45,10)
j = linspace(0,200,10)
for i_val in i
plot(i,K(i,j))
end
This gives me the following Error:
isless has no method matching isless(::Int64, ::Array{Float64,1})
while loading In[51], in expression starting on line 3
in Kvc at In[17]:2 in anonymous at no file:4
Obviously, my function cant deal with an array.
Next try:
i = linspace(0,200,11)
j = linspace(0,45,11)
for i_val in i
plot(i_val,map(K,i_val,j))
end
gives me a empty plot only with axes
Can anybody please give me a hint...
EDIT
A simpler example:
using PyPlot
function P(n,M)
return (M*n^3)/9550
end
M = linspace(1,5,5)
n = linspace(0,3000,3001)
for M_val in M
plot(n,P(n,M_val))
end
show()
Solution
OK, with your help I found this solution for the shortened example which works for me as intended:
function P(n,M)
result = Array(Float64, length(n))
for (idx, val) in enumerate(n)
result[idx] = (M*val^3)/9550
end
return result
end
n = linspace(0,3000,3001)
for M_val = 1:5
plot(n,P(n,M_val))
end
show()
This gives me what I wanted for this shortened example. The remainig question is: could it be done in a simpler more elegant way?
I'll try to apply it to the original example and post it when I'll succed.
I don't completely follow all the details of what you're trying to accomplish, but here are examples on how you can modify a couple of your functions so that they accept and return arrays:
function Kvc(vc)
result = Array(Float64, length(vc))
for (idx, val) in enumerate(vc)
if val <= 0
result[idx] = 0
elseif val < 20
result[idx] = (100/val)^0.1
elseif val < 100
result[idx] = 2.023/(val^0.153)
elseif val == 100
result[idx] = 1
elseif val > 100
result[idx] = 1.380/(val^0.07)
else
result[idx] = 0
end
end
return result
end
function Kgamma(gamma_t)
return ones(length(gamma_t))-((gamma_t - gamma_0)/100)
end
Also, for your loop, I think you probably want something like:
for i_val in i
plot(i_val,K(i_val,j))
end
rather than plot(i, K(i,j), as that would just print the same thing over and over.
< is defined for scalars. I think you need to broadcast it for arrays, i.e. use .<. Example:
julia> x = 2
2
julia> x < 3
true
julia> x < [3 4]
ERROR: MethodError: no method matching isless(::Int64, ::Array{Int64,2})
Closest candidates are:
isless(::Real, ::AbstractFloat)
isless(::Real, ::Real)
isless(::Integer, ::Char)
in <(::Int64, ::Array{Int64,2}) at .\operators.jl:54
in eval(::Module, ::Any) at .\boot.jl:234
in macro expansion at .\REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at .\event.jl:46
julia> x .< [3 4]
1x2 BitArray{2}:
true true

Count unknown variables from a table

I have a problem here... if I have a table with few repeated string results. I want to know the value am the ammount of each.
For example. A function return an unknown "letters" and with unknown quantities in quantity
Function () return Table end
Table ={'a','a','c','b','b','a',...}
And I want to get this.
table.a={'a','a','a'}
table.b={'b','b'}
table.c={'c'}
....
....
I have no clue how to solve it...
Write a function, which creates a hash map of these things:
function RepetitionCounter(tInput)
local tCounter = {}
for i, v in ipairs(tInput) do
tCounter[v] = (tCounter[v] or 0) + 1
end
return tCounter
end
which you'll use as follows:
local tData = {'a','a','c','b','b','a',...}
local tCounts = RepetitionCounter(tData)
and the table tCounts would be as follows:
tCounts.a = 3
tCounts.b = 2
tCounts.c = 1
Modifying the function above by just a little, you can get the desired output. Replace the following line:
tCounter[v] = (tCounter[v] or 0) + 1
with
if not tCounter[v] then
tCounter[v] = {}
else
table.insert(tCounter[v], v)
end

Differences between two tables in Lua

I have two tables in lua (In production, a has 18 elements and b has 8):
local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}
I need to return 'a' omitting any common elements from 'b' -- {1,2,4,6} similar to the ruby command a-b (if a and b were arrays).
The best lua logic I have been able to come up with is:
local function find(a, tbl)
for _,a_ in ipairs(tbl) do if a_==a then return true end end
end
function difference(a, b)
local ret = {}
for _,a_ in ipairs(a) do
if not find(a_,b) then table.insert(ret, a_) end
end
return ret
end
local a = {1,2,3,4,5,6}
local b = {3,5,7,8,9}
local temp = {}
temp = difference(a,b)
print(temp[1],temp[2],temp[3],temp[4])
I need to loop through these table comparison pretty quick (min 10K times a second in production). Is there a cleaner way to do this?
======
This is part of a redis server side script and I have to protect my Redis CPU. Outside of a clean Lua process I have two other options:
1.Create two redis temp keys then run sinter for a big(O) of 42
18 sadd(a)
8 sadd(b)
16 sinter(a,b)
2.Return both a and b to ruby do the array comparison and send back the result.
Network cost of the back and fourth of a few thousand connections a second will be a drain on resources.
Try this:
function difference(a, b)
local aa = {}
for k,v in pairs(a) do aa[v]=true end
for k,v in pairs(b) do aa[v]=nil end
local ret = {}
local n = 0
for k,v in pairs(a) do
if aa[v] then n=n+1 ret[n]=v end
end
return ret
end
You could do this (not tested):
function difference(a, b)
local ai = {}
local r = {}
for k,v in pairs(a) do r[k] = v; ai[v]=true end
for k,v in pairs(b) do
if ai[v]~=nil then r[k] = nil end
end
return r
end
If you can modify a then it is even shorter:
function remove(a, b)
local ai = {}
for k,v in pairs(a) do ai[v]=true end
for k,v in pairs(b) do
if ai[v]~=nil then a[k] = nil end
return r
end
If your tables are sorted you could also do a parallel sweep of the two tables together, something like the following pseudo code:
function diff(a, b)
Item = front of a
Diff = front of b
While Item and Diff
If Item < Diff then
Item is next of a
Else if Item == Diff then
remove Item from a
Item = next of a
Diff = next of b
Else # else Item > Diff
Diff = next of b
This doesn't use any extra tables. Even if you want new table instead of in-place diff, only one new table. I wonder how it would compare to the hash table method (remove).
Note that it doesn't matter how many times you loop, if a and b are small then there will be no major difference between these and your alg. You'll need at least 100 items in a and in b, maybe even 1000.
Maybe something like that:
function get_diff (t1, t2)
local diff = {}
local bool = false
for i, v in pairs (t1) do
if t2 and type (v) == "table" then
local deep_diff = get_diff (t1[i], t2[i])
if deep_diff then
diff[i] = deep_diff
bool = true
end
elseif t2 then
if not (t1[i] == t2[i]) then
diff[i] = t1[i] .. ' -- not [' .. t2[i] .. ']'
bool = true
end
else
diff[i] = t1[i]
bool = true
end
end
if bool then
return diff
end
end
local t1 = {1, 2, 3, {1, 2, 3}}
local t2 = {1, 2, 3, {1, 2, 4}}
local diff = get_diff (t1, t2)
Result:
diff = {
nil,
nil,
nil,
{
[3] = "3 -- not [4]"
}
}