Astar pathfinding sometimes stops working - a-star

I'm doing a project when i need to search a path in maze ( matrix of 0's and 1's ), given a origin ( a position tuple ) and an destination.
It works, but sometimes it's just stops, enters in the while loop and while opening the nodes, never reaches the end node... and i don't know why.
I find that algorithm on "medium" site.
´´´
def astar(maze, start, end,bonus,exit_door):
maze = [ [0 if x == 0 else 1 for x in y] for y in maze ]
x_end=end[0]
y_end=end[1]
maze[x_end][y_end]=0
if bonus:
x_bonus=bonus[0]
y_bonus=bonus[1]
maze[x_bonus][y_bonus]=0
if exit_door:
x_exit=exit_door[0]
y_exit=exit_door[1]
maze[x_exit][y_exit]=0
# Create start and end node
start_node = Node(None, start)
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end)
end_node.g = end_node.h = end_node.f = 0
# Initialize both open and closed list
open_list = []
closed_list = []
# Add the start node
open_list.append(start_node)
# Loop until you find the end
while len(open_list) > 0 :
tempo=tempo+1
# Get the current node
current_node = open_list[0]
current_index = 0
for index, item in enumerate(open_list):
if item.f <= current_node.f:
current_node = item
current_index = index
# Pop current off open list, add to closed list
open_list.pop(current_index)
closed_list.append(current_node)
# Found the goal
if current_node == end_node:
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return path[::-1] # Return reversed path
# Generate children
children = []
####
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: # Adjacent squares
# Get node position
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])
## vê cada quadrado adjacente ao nosso current
# Make sure within range
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0:
continue
# Make sure walkable terrain
if maze[node_position[0]][node_position[1]] != 0:
continue
# Create new node
new_node = Node(current_node, node_position)
# Append
children.append(new_node)
## children apenas contém os nós que correspondem a quadrados para o quais o agente pode andar
# Loop through children
for child in children:
# Child is on the closed list
for closed_child in closed_list:
if child == closed_child:
continue
# Create the f, g, and h values
child.g = current_node.g + 1
child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2)
child.f = child.g + child.h
# Child is already in the open list
for open_node in open_list:
if child == open_node and child.g > open_node.g:
continue
# Add the child to the open list
open_list.append(child)
´´´

This is not working becouse u have 2 misstake
for closed_child in closed_list:
if child == closed_child:
continue
and
for open_node in open_list:
if child == open_node and child.g > open_node.g:
continue
operator continue exits iner for. You should use another type for open_list and closed_list.

Related

Attempt to index field (a nil value), for an Object

I have a problem with trying to add things to a LOVE2D version of Match-3. (From the CS50 course)
I added a function swapTiles() into my Board class and made a class object called self.board in a Class called PlayState. Then when I try to access the new function, it says this error:
Error
src/states/PlayState.lua:155: attempt to index field 'board' (a nil value)
I'll provide my Board and PlayState class below:
Board: (keep in mind the new function is literally in the code)
Board = Class{}
function Board:init(x, y, level) -- Added "level" as an integer for the block variations.
self.x = x
self.y = y
self.matches = {}
self.level = level
self:initializeTiles()
end
function Board:swapTiles(tile1, tile2)
-- swap grid positions of tiles
local tempX = tile1.gridX
local tempY = tile1.gridY
tile1.gridX = tile2.gridX
tile1.gridY = tile2.gridY
tile2.gridX = tempX
tile2.gridY = tempY
-- swap tiles in the tiles table
self.tiles[tile1.gridY][tile1.gridX] = tile1
self.tiles[tile2.gridY][tile2.gridX] = tile2
end
function Board:initializeTiles()
self.tiles = {}
-- There should only be two shiny tiles.
for tileY = 1, 8 do
-- empty table that will serve as a new row
table.insert(self.tiles, {})
for tileX = 1, 8 do
self.isPowerup = false
if math.random(1, 25) == 4 then
self.isPowerup = true
end
-- create a new tile at X,Y with a random color and variety
table.insert(self.tiles[tileY], Tile(tileX, tileY, math.random(18), math.min(8, math.random(1, self.level)), self.isPowerup))
end
end
while self:calculateMatches() do
-- recursively initialize if matches were returned so we always have
-- a matchless board on start
self:initializeTiles()
end
end
--[[
Goes left to right, top to bottom in the board, calculating matches by counting consecutive
tiles of the same color. Doesn't need to check the last tile in every row or column if the
last two haven't been a match.
]]
function Board:calculateMatches()
local matches = {}
-- how many of the same color blocks in a row we've found
local matchNum = 1
-- horizontal matches first
for y = 1, 8 do
local colorToMatch = self.tiles[y][1].color
matchNum = 1
-- every horizontal tile
for x = 2, 8 do
-- if this is the same color as the one we're trying to match...
if self.tiles[y][x].color == colorToMatch then
matchNum = matchNum + 1
else
-- set this as the new color we want to watch for
colorToMatch = self.tiles[y][x].color
-- if we have a match of 3 or more up to now, add it to our matches table
if matchNum >= 3 then
local match = {}
-- go backwards from here by matchNum
for x2 = x - 1, x - matchNum, -1 do
-- add each tile to the match that's in that match
table.insert(match, self.tiles[y][x2])
-- Shiny Check
if self.tiles[y][x2].isShiny == true then
for i = 1, 8 do
table.insert(match, self.tiles[y][i])
end
end
end
-- add this match to our total matches table
table.insert(matches, match)
end
-- don't need to check last two if they won't be in a match
if x >= 7 then
break
end
matchNum = 1
end
end
-- account for the last row ending with a match
if matchNum >= 3 then
local match = {}
-- go backwards from end of last row by matchNum
for x = 8, 8 - matchNum + 1, -1 do
table.insert(match, self.tiles[y][x])
end
table.insert(matches, match)
end
end
-- vertical matches
for x = 1, 8 do
local colorToMatch = self.tiles[1][x].color
matchNum = 1
-- every vertical tile
for y = 2, 8 do
if self.tiles[y][x].color == colorToMatch then
matchNum = matchNum + 1
else
colorToMatch = self.tiles[y][x].color
if matchNum >= 3 then
local match = {}
for y2 = y - 1, y - matchNum, -1 do
table.insert(match, self.tiles[y2][x])
if self.tiles[y2][x].isShiny == true then
for i = 1, 8 do
table.insert(match, self.tiles[i][x])
end
end
end
table.insert(matches, match)
end
matchNum = 1
-- don't need to check last two if they won't be in a match
if y >= 7 then
break
end
end
end
-- account for the last column ending with a match
if matchNum >= 3 then
local match = {}
-- go backwards from end of last row by matchNum
for y = 8, 8 - matchNum, -1 do
table.insert(match, self.tiles[y][x])
end
table.insert(matches, match)
end
end
-- store matches for later reference
self.matches = matches
-- return matches table if > 0, else just return false
return #self.matches > 0 and self.matches or false
end
--[[
Remove the matches from the Board by just setting the Tile slots within
them to nil, then setting self.matches to nil.
]]
function Board:removeMatches()
for k, match in pairs(self.matches) do
for k, tile in pairs(match) do
self.tiles[tile.gridY][tile.gridX] = nil
end
end
self.matches = nil
end
--[[
Shifts down all of the tiles that now have spaces below them, then returns a table that
contains tweening information for these new tiles.
]]
function Board:getFallingTiles()
-- tween table, with tiles as keys and their x and y as the to values
local tweens = {}
-- for each column, go up tile by tile till we hit a space
for x = 1, 8 do
local space = false
local spaceY = 0
local y = 8
while y >= 1 do
-- if our last tile was a space...
local tile = self.tiles[y][x]
if space then
-- if the current tile is *not* a space, bring this down to the lowest space
if tile then
-- put the tile in the correct spot in the board and fix its grid positions
self.tiles[spaceY][x] = tile
tile.gridY = spaceY
-- set its prior position to nil
self.tiles[y][x] = nil
-- tween the Y position to 32 x its grid position
tweens[tile] = {
y = (tile.gridY - 1) * 32
}
-- set space back to 0, set Y to spaceY so we start back from here again
space = false
y = spaceY
spaceY = 0
end
elseif tile == nil then
space = true
if spaceY == 0 then
spaceY = y
end
end
y = y - 1
end
end
-- create replacement tiles at the top of the screen
for x = 1, 8 do
for y = 8, 1, -1 do
local tile = self.tiles[y][x]
-- if the tile is nil, we need to add a new one
if not tile then
local tile = Tile(x, y, math.random(18), math.random(1, self.level))
tile.y = -32
self.tiles[y][x] = tile
tweens[tile] = {
y = (tile.gridY - 1) * 32
}
end
end
end
return tweens
end
function Board:getNewTiles()
return {}
end
function Board:testForMatches()
for y = 1, 8 do
for x = 1, 8 do
-- Test for left swap
if x > 1 then
end
end
end
end
function Board:render()
for y = 1, #self.tiles do
for x = 1, #self.tiles[1] do
self.tiles[y][x]:render(self.x, self.y)
end
end
end
Here's my PlayState: (look for PlayState:swapTiles(), keep in mind that the self.board is being used several times for and works fine, except when i try calling self.board:swapTiles().)
PlayState = Class{__includes = BaseState}
function PlayState:init()
-- start our transition alpha at full, so we fade in
self.transitionAlpha = 255
-- position in the grid which we're highlighting
self.boardHighlightX = 0
self.boardHighlightY = 0
-- timer used to switch the highlight rect's color
self.rectHighlighted = false
-- flag to show whether we're able to process input (not swapping or clearing)
self.canInput = true
-- tile we're currently highlighting (preparing to swap)
self.highlightedTile = nil
self.score = 0
self.timer = 60
-- set our Timer class to turn cursor highlight on and off
Timer.every(0.5, function()
self.rectHighlighted = not self.rectHighlighted
end)
-- subtract 1 from timer every second
Timer.every(1, function()
self.timer = self.timer - 1
-- play warning sound on timer if we get low
if self.timer <= 5 then
gSounds['clock']:play()
end
end)
end
function PlayState:enter(params)
-- grab level # from the params we're passed
self.level = params.level
-- spawn a board and place it toward the right
self.board = params.board or Board(VIRTUAL_WIDTH - 272, 16)
-- grab score from params if it was passed
self.score = params.score or 0
-- score we have to reach to get to the next level
self.scoreGoal = self.level * 1.25 * 1000
end
function PlayState:update(dt)
if love.keyboard.wasPressed('escape') then
love.event.quit()
end
-- go back to start if time runs out
if self.timer <= 0 then
-- clear timers from prior PlayStates
Timer.clear()
gSounds['game-over']:play()
gStateMachine:change('game-over', {
score = self.score
})
end
-- go to next level if we surpass score goal
if self.score >= self.scoreGoal then
-- clear timers from prior PlayStates
-- always clear before you change state, else next state's timers
-- will also clear!
Timer.clear()
gSounds['next-level']:play()
-- change to begin game state with new level (incremented)
gStateMachine:change('begin-game', {
level = self.level + 1,
score = self.score
})
end
if self.canInput then
-- move cursor around based on bounds of grid, playing sounds
if love.keyboard.wasPressed('up') then
self.boardHighlightY = math.max(0, self.boardHighlightY - 1)
gSounds['select']:play()
elseif love.keyboard.wasPressed('down') then
self.boardHighlightY = math.min(7, self.boardHighlightY + 1)
gSounds['select']:play()
elseif love.keyboard.wasPressed('left') then
self.boardHighlightX = math.max(0, self.boardHighlightX - 1)
gSounds['select']:play()
elseif love.keyboard.wasPressed('right') then
self.boardHighlightX = math.min(7, self.boardHighlightX + 1)
gSounds['select']:play()
end
-- if we've pressed enter, to select or deselect a tile...
if love.keyboard.wasPressed('enter') or love.keyboard.wasPressed('return') then
-- if same tile as currently highlighted, deselect
local x = self.boardHighlightX + 1
local y = self.boardHighlightY + 1
-- if nothing is highlighted, highlight current tile
if not self.highlightedTile then
self.highlightedTile = self.board.tiles[y][x]
-- if we select the position already highlighted, remove highlight
elseif self.highlightedTile == self.board.tiles[y][x] then
self.highlightedTile = nil
-- if the difference between X and Y combined of this highlighted tile
-- vs the previous is not equal to 1, also remove highlight
elseif math.abs(self.highlightedTile.gridX - x) + math.abs(self.highlightedTile.gridY - y) > 1 then
gSounds['error']:play()
self.highlightedTile = nil
else
self:swapTiles(self.highlightedTile, self.board.tiles[y][x], true)
end
end
end
Timer.update(dt)
end
function PlayState:swapTiles(tile1, tile2, swapBackAtNoMatch)
local tile1 = tile1
local tile2 = tile2
local swapBackAtNoMatch = swapBackAtNoMatch
self.board:swapTiles(tile1, tile2) -- Causes the nil error.
if swapBackAtNoMatch then
-- tween coordinates between two swapping tiles
Timer.tween(0.1, {
[tile1] = {x = tile2.x, y = tile2.y},
[tile2] = {x = tile1.x, y = tile1.y}
})
-- once they've swapped, tween falling blocks
:finish(function ()
local matches = self.board:calculateMatches()
if matches then
self.calculateMatches(matches)
else
-- swap back if there's no match
self.swapTiles(tile1, tile2, false)
gSounds['error']:play()
end
end)
else
-- tween coordinates between the two so they swap
Timer.tween(0.1, {
[tile1] = {x = tile2.x, y = tile2.y},
[tile2] = {x = tile1.x, y = tile1.y}})
end
end
--[[
Calculates whether any matches were found on the board and tweens the needed
tiles to their new destinations if so. Also removes tiles from the board that
have matched and replaces them with new randomized tiles, deferring most of this
to the Board class.
]]
function PlayState:calculateMatches()
self.highlightedTile = nil
-- if we have any matches, remove them and tween the falling blocks that result
local matches = self.board:calculateMatches()
if matches then
gSounds['match']:stop()
gSounds['match']:play()
-- add score for each match
for k, match in pairs(matches) do
local varietyPoints = 0 -- We'll keep track of the bonus variety points here
-- We'll use vareity to calculate points for each tile within a match
for j, tiles in pairs(match) do
varietyPoints = varietyPoints + tiles.variety * 25
end
self.score = self.score + (#match * 50) + varietyPoints
-- Also add one second times the number of match to the timer
self.timer = self.timer + #match * 1
end
-- remove any tiles that matched from the board, making empty spaces
self.board:removeMatches()
-- gets a table with tween values for tiles that should now fall
local tilesToFall = self.board:getFallingTiles()
-- first, tween the falling tiles over 0.25s
Timer.tween(0.25, tilesToFall):finish(function()
local newTiles = self.board:getNewTiles()
-- then, tween new tiles that spawn from the ceiling over 0.25s to fill in
-- the new upper gaps that exist
Timer.tween(0.25, newTiles):finish(function()
-- recursively call function in case new matches have been created
-- as a result of falling blocks once new blocks have finished falling
self:calculateMatches()
end)
end)
-- if no matches, we can continue playing
else
self.canInput = true
end
end
Honestly doesn't make much sense. Please help!
function PlayState:swapTiles(tile1, tile2, swapBackAtNoMatch) end
is syntactic sugar for
PlayState.swaptiles = function(self, tile1, tile2, swapBackAtNoMatch) end
That's the reason why you can work with self inside that function.
A function defined like that needs to be called using the colon operator as well to make this work. Or you explicitly provide the table as first parameter.
Hence in your call self.swapTiles(tile1, tile2, false)
self is going to be tile1
tile1.board is nil so self.board is nil in this function call which causes the error
You have to call self:swapTiles(tile1, tile2, false) or self.swapTiles(self, tile1, tile2, false)
Please make sure you fully understand the colon syntax.

Merge Sort on Linked List

Merge Sort functions with only some inputs when run on a linked list. If I include 0 in the list of inputs, only 0 is returned from the final print() call. I don't know what I'm doing wrong
class StackNode(object):
def __init__(self, data):
self.data = data
self.prev = None
class Stack(object):
def __init__(self):
self.head = None
self.count = 0
def push(self, data):
if (self.head == None):
self.head = StackNode(data)
self.count += 1
return
node = StackNode(data)
node.prev = self.head
self.head = node
self.count += 1
return
def pop(self):
node = self.head
self.head = self.head.prev
self.count -= 1
return node
def print(self):
node = self.head
if(node == None):
return
print(node.data)
while(node.prev):
node = node.prev
print(node.data)
def MergeSort(self, h):
if h == None or h.prev == None:
return h
middle = self.GetMiddle(h)
nextToMiddle = middle.prev
middle.prev = None
left = self.MergeSort(h)
right = self.MergeSort(nextToMiddle)
sortedList = self.SortedMerge(left, right)
return sortedList
def SortedMerge(self, a, b):
if a is None:
return b
if b is None:
return a
if(a.data > b.data):
result = a
a.prev = self.SortedMerge(a.prev, b)
else:
result = b
b.prev = self.SortedMerge(b.prev, a)
return result
def GetMiddle(self, head):
if head == None:
return head
slow = head
fast = head
while(fast.prev != None and fast.prev.prev != None):
slow = slow.prev
fast = fast.prev.prev
return slow
a = Stack()
a.push(2)
a.push(5)
a.push(1)
a.push(4)
a.push(3)
a.push(7)
a.print()
a.MergeSort(a.head)
print("after: ")
a.print()
I transcribed my code directly from the linked list merge sort example given on geeksforgeeks.com, with the only difference being that my code creates a stack instead of a queue
MergeSort returns the head of a sorted list, so the call in the main code should be:
a.head = a.MergeSort(a.head)
For a sorted stack, it would seem that the result of doing successive list.pop() should return the nodes in data order, but the code is using ">" instead of "<=" in the compare, reversing the order.
Python 2.7 complained about using the name print for the class print function, and also complained about the 5 (instead of 4) spaces before "def SortedMerge(self, a, b):"
SortedMerge() does one level of recursion for every node merged. For a large list, the program will get stack overflow. Since the list class includes a count, the code could use list.count//2 to determine the number of nodes to advance to reach the midpoint, then use (count//2) for the size of the left half and (count-(count//2)) for the size of the right half. A bottom up merge sort is faster still. However, with python, the overhead of interpreting code is so large that I don't know if it will make a difference. Here is a link to both top down and bottom up merge sort for a linked list, in java, that use a common merge function:
Merge Sort for Singly Linked List seems to remove any numbers larger than the final number I input into the list
I converted the code to python. The merge function is the same for both examples. Note the sort logic is the same, only the push and pop functions result in the linked list acting as a stack. Merge function:
def Merge(self, a, b):
if a is None:
return b
if b is None:
return a
r = StackNode(0) # dummy node
d = r
while(True):
if(a.data <= b.data):
d.prev = a
d = a
a = a.prev
if(a == None):
d.prev = b
break
else:
d.prev = b
d = b
b = b.prev
if(b == None):
d.prev = a
break
return r.prev
Top down example:
def MergeSort(self):
if(self.count < 2):
return
self.head = self.MergeSortR(self.head, self.count)
def MergeSortR(self, h, n):
if(n < 2):
return h
n2 = n//2
t = self.Scan(h, n2-1)
m = t.prev
t.prev = None
h = self.MergeSortR(h, n2)
m = self.MergeSortR(m, n-n2)
h = self.Merge(h, m)
return h
def Scan(self, h, n):
while(n > 0):
h = h.prev
n = n-1
return h
Bottom up example:
def MergeSort(self):
if(self.count < 2):
return
an = [None] * 32
node = self.head
while(node != None):
prev = node.prev
node.prev = None
i = 0
while((i < 32) and (an[i] != None)):
node = self.Merge(an[i], node)
an[i] = None
i = i+1
if(i == 32):
i = i-1
an[i] = node
node = prev
for i in xrange (0, 32):
node = self.Merge(an[i], node)
self.head = node
Test code for 512K nodes. On my system, top down takes about 4.5 seconds, bottom up about 3.9 seconds. To get an idea of the overhead of Python, bottom up in C takes about 0.06 seconds.
import random
from time import time
p = [random.randint(0, 2147483647) for r in xrange(512*1024)]
a = Stack()
for i in xrange (0, len(p)):
a.push(p[i])
s = time()
a.MergeSort()
e = time()
print e - s
for i in xrange (0, len(p)):
p[i] = a.pop().data
for i in xrange (1, len(p)):
if(p[i-1] > p[i]):
print("error")
break

Minimum Change Maker Returning Optimal Solution and No Solution

I need Help adding a if clause to my Change Maker, so that if say I have denominations of coins that can't equal the input coin value. For Example I have Coins worth 2,4,6 and I have a Value of 1. I Want it to return Change Not Possible I tried adding a clause to it below but when I test it I get 1.#INF
I also am curious how I can find the optimal coin solution, So on top of saying the minimum number of coins it returns the optimal coin setup if there is one.
function ChangeMaking(D,n)
--[[
//Applies dynamic programming to find the minimum number of coins
//of denominations d1< d2 < . . . < dm where d1 = 1 that add up to a
//given amount n
//Input: Positive integer n and array D[1..m] of increasing positive
// integers indicating the coin denominations where D[1]= 1
//Output: The minimum number of coins that add up to n
]]
F = {} -- F is List Array of Coins
m = tablelength(D)
F[0] = 0
for i =1,n do
temp = math.huge
j = 1
while j <= m and i >= D[j] do
temp = math.min(F[ i - D[j] ], temp)
j = j + 1
end
F[i] = temp + 1
end
--I wanted to Catch the failed Solution here but I return 1.#INF instead
--if F[n] <= 0 and F[n] == 1.#INF then print("No Change Possible") return end
return F[n]
end
function main()
--[[
//Prints a Greeting, Asks for Denominations separated by spaces.
// Iterates through the input and assigns values to table
// Table is then input into ChangeMaker, and a while loop takes an n value for user input.
// User Enters 0 to end the Loop
]]
io.write("Hello Welcome the to Change Maker - LUA Edition\nEnter a series of change denominations, separated by spaces: ")
input = io.read()
deno = {}
for num in input:gmatch("%d+") do table.insert(deno,tonumber(num)) end
local i = 1
while i ~= 0 do
io.write("Please Enter Total for Change Maker, When Finished Enter 0 to Exit: ")
input2 = io.read("*n")
if input2 ~= 0 then io.write("\nMinimum # of Coins: " .. ChangeMaking(deno,input2).."\n") end
if input2 == 0 then i=0 print("0 Entered, Exiting Change Maker") end
end
end
function tablelength(T)
--[[
//Function for grabbing the total length of a table.
]]
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
main()

Lua Acessing table values within nested table

I'm trying to test certain variables on a grid made out of nested tables. However no matter what I try it wont give me the values stored within the variables only the data type or a nil value
y = {}
for _y = 0,16 do
for _x = 0,16 do
x = {}
x.x = _x
x.y = _y
x.v = flr(rnd(2))
if x.x < 1 or x.x > 14 then
x.v = 3
end
if x.v == 0 then
x.v = "."
elseif x.v ==1 then
x.v = ","
else
x.v = "0"
end
add(y,x)
end
end
I've tried accessing the value using
print(t[1][3])
But this only prints back a nil value, how would I code this to show whats stored within the value within these two tables?
You have the nesting as follows:
y = {x_1, x_2, x_3, ...}
where, each of x_i is of the form:
x = {
x = p,
y = q,
v = r
}
so, you will have the indexing for each x element as y[i], and each y[i] contains 3 attributes:
print(y[1].x)
will give you x_1.x
You want to create a 2-dimensional table, but only create a 1-dimensional one.
Fix your code to look somewhat like this
y = {}
for _y=1,16 do
y[_y] = {}
for _x=1,16 do
y[_y][_x]= "your data"
end
end

Generate and manipulate a table of "complex" objects in CoronaSDK

I'm trying to generate 40 circles with text and I want to be able to use them and handle them later.
According to several post I found here and on corona forums, I'm doing it well but, in all the examples, is only with one "display" object... not with several so I'm not sure if it's possible or maybe it needs something different.
After some introduction... here the code:
function _.spawn(params)
local orb = display.newCircle( display.contentWidth/2, display.contentHeight/2, 40 ) -- creates the orb shape
orb.orbTable = params.orbTable --assign the internal table
orb.index = #orb.orbTable + 1 -- takes control of the index
orb.orbTable[orb.index] = orb -- assign a orb to the internal table
orb:setFillColor( unpack(params.color) ) -- change the color according to the rules above
orb.x = params.x -- control the X position of the orb
orb.y = params.y --control the Y position of the orb
orb.alpha = 1 -- borns with alpha = 0
orb.value = params.value -- assign the internal value of the orb (1-10)
--local orbText = display.newText( orb.value, orb.x+2, orb.y-5, "Aniron", 40 ) -- generates the value on the ball
--orbText.orbTable = params.orbTable
--orbText.index = #orbText.orbTable + 1
--orbText.orbTable[orbText.index] = orbText
--orbText:setFillColor( 0,0,0 )
--orbText.alpha = 1
--The objects group
orb.group = params.group or nil
--If the function call has a parameter named group then insert it into the specified group
orb.group:insert(orb)
--orb.group:insert(orbText)
--Insert the object into the table at the specified index
orb.orbTable[orb.index] = orb
return orb -- returns the orb to have control of it
end
The function to generate all the objects I need is:
function _.generateDeck()
for i = 1, 40 do -- loop to generate the 40 orbs
internalValue = internalValue + 1 -- counter to assigns the right values
if (internalValue > 10) then -- if the internal value is more than 10 starts again (only 1-10)
internalValue = 1
end
if (i >= 1 and i <= 10) then -- assign RED color to the first 10 orbs
completeDeck[i] = _.spawn({color = {196/255,138/255,105/255}, group = orbsGroup, x = 100, y = display.contentHeight / 2, value = internalValue, orbTable = completeDeck})
elseif (i >= 11 and i <= 20) then -- assigns YELLOW color to the next 10 orbs
completeDeck[i] = _.spawn({color = {229/255,214/255,142/255}, group = orbsGroup, x = 100, y = display.contentHeight / 2, value = internalValue, orbTable = completeDeck})
elseif (i >= 11 and i <= 30) then -- assigns BLUE color to the next 10 orbs
completeDeck[i] = _.spawn({color = {157/255,195/255,212/255}, group = orbsGroup, x = 100, y = display.contentHeight / 2, value = internalValue, orbTable = completeDeck})
elseif (i >= 11 and i <= 40) then -- assigns GREEN color to the next 10 balls
completeDeck[i] = _.spawn({color = {175/255,181/255,68/255}, group = orbsGroup, x = 100, y = display.contentHeight / 2, value = internalValue, orbTable = completeDeck})
end
end
end
After calling the function, it generates the circles correctly and I can read the value:
for i = 1, #completeDeck do
print("Complete Deck Value ("..i.."): "..completeDeck[i].value)
end
But if I uncomment the lines regarding the newText (orbText) then I'm not able to read the values... (value is a nil value)
I guess I need to create a displayGroup with the objects I want inside (circle and text), then "spawn" it, modifying the values? In that case... how can I refer to the object inside the displayGroup?
I think I'm mixing different concepts.
In Lua, objects are tables and to create an object composed of existing objects, we create a table with and add the objects to it as values. The code below creates an objects with orb and orbText which can be accessed by object.orb or object.orbText
function _.spawn(params)
local orb = display.newCircle(display.contentWidth/2, display.contentHeight/2, 40) -- creates the orb shape
orb:setFillColor(unpack(params.color))
orb.x = params.x
orb.y = params.y
orb.alpha = 1
local orbText = display.newText(param.value, param.x + 2, param.y - 5, "Aniron", 40)
orbText:setFillColor(0, 0, 0)
orbText.alpha = 1
-- create an object with orb and orbText as values
local object = {orb = orb, orbText = orbText}
-- add more values to the object
object.value = params.value
object.index = #params.orbTable + 1
params.orbTable[object.index] = object
return object
end
Now to use the object:
for i, object in ipairs(completeDeck) do
print(object.value)
end

Resources