First commit
commit
4f84fa8348
|
@ -0,0 +1,206 @@
|
||||||
|
--[[
|
||||||
|
A* algorithm for LUA
|
||||||
|
Ported to LUA by Altair
|
||||||
|
21 septembre 2006
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function CalcMoves(mapmat, px, py, tx, ty) -- Based on some code of LMelior but made it work and improved way beyond his code, still thx LMelior!
|
||||||
|
--[[ PRE:
|
||||||
|
mapmat is a 2d array
|
||||||
|
px is the player's current x
|
||||||
|
py is the player's current y
|
||||||
|
tx is the target x
|
||||||
|
ty is the target y
|
||||||
|
|
||||||
|
Note: all the x and y are the x and y to be used in the table.
|
||||||
|
By this I mean, if the table is 3 by 2, the x can be 1,2,3 and the y can be 1 or 2.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--[[ POST:
|
||||||
|
closedlist is a list with the checked nodes.
|
||||||
|
It will return nil if all the available nodes have been checked but the target hasn't been found.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
-- variables
|
||||||
|
local openlist={} -- Initialize table to store possible moves
|
||||||
|
local closedlist={} -- Initialize table to store checked gridsquares
|
||||||
|
local listk=1 -- List counter
|
||||||
|
local closedk=0 -- Closedlist counter
|
||||||
|
local tempH=math.abs(px-tx)+math.abs(py-ty)
|
||||||
|
local tempG=0
|
||||||
|
openlist[1]={x=px, y=py, g=0, h=tempH, f=0+tempH ,par=1} -- Make starting point in list
|
||||||
|
local xsize=table.getn(mapmat[1]) -- horizontal map size
|
||||||
|
local ysize=table.getn(mapmat) -- vertical map size
|
||||||
|
local curbase={} -- Current square from which to check possible moves
|
||||||
|
local basis=1 -- Index of current base
|
||||||
|
|
||||||
|
-- Growing loop
|
||||||
|
while listk>0 do
|
||||||
|
|
||||||
|
-- Get the lowest f of the openlist
|
||||||
|
local lowestF=openlist[listk].f
|
||||||
|
basis=listk
|
||||||
|
for k=listk,1,-1 do
|
||||||
|
if openlist[k].f<lowestF then
|
||||||
|
lowestF=openlist[k].f
|
||||||
|
basis=k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
closedk=closedk+1
|
||||||
|
table.insert(closedlist,closedk,openlist[basis])
|
||||||
|
|
||||||
|
curbase=closedlist[closedk] -- define current base from which to grow list
|
||||||
|
|
||||||
|
local rightOK=true
|
||||||
|
local leftOK=true -- Booleans defining if they're OK to add
|
||||||
|
local downOK=true -- (must be reset for each while loop)
|
||||||
|
local upOK=true
|
||||||
|
|
||||||
|
-- Look through closedlist
|
||||||
|
if closedk>0 then
|
||||||
|
for k=1,closedk do
|
||||||
|
if closedlist[k].x==curbase.x+1 and closedlist[k].y==curbase.y then
|
||||||
|
rightOK=false
|
||||||
|
end
|
||||||
|
if closedlist[k].x==curbase.x-1 and closedlist[k].y==curbase.y then
|
||||||
|
leftOK=false
|
||||||
|
end
|
||||||
|
if closedlist[k].x==curbase.x and closedlist[k].y==curbase.y+1 then
|
||||||
|
downOK=false
|
||||||
|
end
|
||||||
|
if closedlist[k].x==curbase.x and closedlist[k].y==curbase.y-1 then
|
||||||
|
upOK=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if next points are on the map and within moving distance
|
||||||
|
if curbase.x+1>xsize then
|
||||||
|
rightOK=false
|
||||||
|
end
|
||||||
|
if curbase.x-1<1 then
|
||||||
|
leftOK=false
|
||||||
|
end
|
||||||
|
if curbase.y+1>ysize then
|
||||||
|
downOK=false
|
||||||
|
end
|
||||||
|
if curbase.y-1<1 then
|
||||||
|
upOK=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If it IS on the map, check map for obstacles
|
||||||
|
--(Lua returns an error if you try to access a table position that doesn't exist, so you can't combine it with above)
|
||||||
|
if curbase.x+1<=xsize and mapmat[curbase.y][curbase.x+1]~=0 then
|
||||||
|
rightOK=false
|
||||||
|
end
|
||||||
|
if curbase.x-1>=1 and mapmat[curbase.y][curbase.x-1]~=0 then
|
||||||
|
leftOK=false
|
||||||
|
end
|
||||||
|
if curbase.y+1<=ysize and mapmat[curbase.y+1][curbase.x]~=0 then
|
||||||
|
downOK=false
|
||||||
|
end
|
||||||
|
if curbase.y-1>=1 and mapmat[curbase.y-1][curbase.x]~=0 then
|
||||||
|
upOK=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if the move from the current base is shorter then from the former parrent
|
||||||
|
tempG=curbase.g+1
|
||||||
|
for k=1,listk do
|
||||||
|
if rightOK and openlist[k].x==curbase.x+1 and openlist[k].y==curbase.y and openlist[k].g>tempG then
|
||||||
|
tempH=math.abs((curbase.x+1)-tx)+math.abs(curbase.y-ty)
|
||||||
|
table.insert(openlist,k,{x=curbase.x+1, y=curbase.y, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
rightOK=false
|
||||||
|
end
|
||||||
|
|
||||||
|
if leftOK and openlist[k].x==curbase.x-1 and openlist[k].y==curbase.y and openlist[k].g>tempG then
|
||||||
|
tempH=math.abs((curbase.x-1)-tx)+math.abs(curbase.y-ty)
|
||||||
|
table.insert(openlist,k,{x=curbase.x-1, y=curbase.y, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
leftOK=false
|
||||||
|
end
|
||||||
|
|
||||||
|
if downOK and openlist[k].x==curbase.x and openlist[k].y==curbase.y+1 and openlist[k].g>tempG then
|
||||||
|
tempH=math.abs((curbase.x)-tx)+math.abs(curbase.y+1-ty)
|
||||||
|
table.insert(openlist,k,{x=curbase.x, y=curbase.y+1, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
downOK=false
|
||||||
|
end
|
||||||
|
|
||||||
|
if upOK and openlist[k].x==curbase.x and openlist[k].y==curbase.y-1 and openlist[k].g>tempG then
|
||||||
|
tempH=math.abs((curbase.x)-tx)+math.abs(curbase.y-1-ty)
|
||||||
|
table.insert(openlist,k,{x=curbase.x, y=curbase.y-1, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
upOK=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add points to openlist
|
||||||
|
-- Add point to the right of current base point
|
||||||
|
if rightOK then
|
||||||
|
listk=listk+1
|
||||||
|
tempH=math.abs((curbase.x+1)-tx)+math.abs(curbase.y-ty)
|
||||||
|
table.insert(openlist,listk,{x=curbase.x+1, y=curbase.y, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add point to the left of current base point
|
||||||
|
if leftOK then
|
||||||
|
listk=listk+1
|
||||||
|
tempH=math.abs((curbase.x-1)-tx)+math.abs(curbase.y-ty)
|
||||||
|
table.insert(openlist,listk,{x=curbase.x-1, y=curbase.y, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add point on the top of current base point
|
||||||
|
if downOK then
|
||||||
|
listk=listk+1
|
||||||
|
tempH=math.abs(curbase.x-tx)+math.abs((curbase.y+1)-ty)
|
||||||
|
table.insert(openlist,listk,{x=curbase.x, y=curbase.y+1, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add point on the bottom of current base point
|
||||||
|
if upOK then
|
||||||
|
listk=listk+1
|
||||||
|
tempH=math.abs(curbase.x-tx)+math.abs((curbase.y-1)-ty)
|
||||||
|
table.insert(openlist,listk,{x=curbase.x, y=curbase.y-1, g=tempG, h=tempH, f=tempG+tempH, par=closedk})
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(openlist,basis)
|
||||||
|
listk=listk-1
|
||||||
|
|
||||||
|
if closedlist[closedk].x==tx and closedlist[closedk].y==ty then
|
||||||
|
return closedlist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function CalcPath(closedlist)
|
||||||
|
--[[ PRE:
|
||||||
|
closedlist is a list with the checked nodes.
|
||||||
|
OR nil if all the available nodes have been checked but the target hasn't been found.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--[[ POST:
|
||||||
|
path is a list with all the x and y coords of the nodes of the path to the target.
|
||||||
|
OR nil if closedlist==nil
|
||||||
|
--]]
|
||||||
|
|
||||||
|
if closedlist==nil then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local path={}
|
||||||
|
local pathIndex={}
|
||||||
|
local last=table.getn(closedlist)
|
||||||
|
table.insert(pathIndex,1,last)
|
||||||
|
|
||||||
|
local i=1
|
||||||
|
while pathIndex[i]>1 do
|
||||||
|
i=i+1
|
||||||
|
table.insert(pathIndex,i,closedlist[pathIndex[i-1]].par)
|
||||||
|
end
|
||||||
|
|
||||||
|
for n=table.getn(pathIndex),1,-1 do
|
||||||
|
table.insert(path,{x=closedlist[pathIndex[n]].x, y=closedlist[pathIndex[n]].y})
|
||||||
|
end
|
||||||
|
|
||||||
|
closedlist=nil
|
||||||
|
return path
|
||||||
|
end
|
|
@ -0,0 +1,172 @@
|
||||||
|
--[[
|
||||||
|
This a little program to test my A* algorithm for LUA
|
||||||
|
Made by Altair
|
||||||
|
21 septembre 2006
|
||||||
|
--]]
|
||||||
|
|
||||||
|
dofile("A-star algorithm release.lua")
|
||||||
|
|
||||||
|
wit=Color.new(255,255,255)
|
||||||
|
rood=Color.new(255,0,0)
|
||||||
|
groen=Color.new(0,255,0)
|
||||||
|
grijs=Color.new(100,100,100)
|
||||||
|
blauw=Color.new(0,0,255)
|
||||||
|
|
||||||
|
x=100
|
||||||
|
y=100
|
||||||
|
player={x=0, y=0, xmove=0, ymove=0, speed=5, path={}, cur=1, pathLength=0, move=false}
|
||||||
|
orderMove=false
|
||||||
|
deler=16
|
||||||
|
xInterval=50
|
||||||
|
yInterval=50
|
||||||
|
|
||||||
|
Player=Image.createEmpty(xInterval-1, yInterval-1)
|
||||||
|
Player:clear(groen)
|
||||||
|
|
||||||
|
map= {
|
||||||
|
{0,0,0,0,0,0,0,0,0},
|
||||||
|
{0,0,0,0,1,0,0,0,0},
|
||||||
|
{0,0,0,0,1,0,0,0,0},
|
||||||
|
{0,0,0,0,1,0,0,0,0},
|
||||||
|
{0,0,0,0,0,0,0,0,0}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGrid(map,xInterval,yInterval,color)
|
||||||
|
local w=table.getn(map[1])
|
||||||
|
local h=table.getn(map)
|
||||||
|
for n=1,w do
|
||||||
|
if n*xInterval<480 then
|
||||||
|
screen:drawLine(n*xInterval,0,n*xInterval,h*yInterval,color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for n=1,h do
|
||||||
|
if n*yInterval<272 then
|
||||||
|
screen:drawLine(0,n*yInterval,w*xInterval,n*yInterval,color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function drawBlock(map,xInterval,yInterval,color)
|
||||||
|
local w=table.getn(map[1])
|
||||||
|
local h=table.getn(map)
|
||||||
|
for n=1,w do
|
||||||
|
for i=1,h do
|
||||||
|
if map[i][n]==1 then
|
||||||
|
screen:fillRect((n-1)*xInterval+1, (i-1)*yInterval+1, xInterval-1, yInterval-1, color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
|
||||||
|
screen:clear()
|
||||||
|
|
||||||
|
drawGrid(map,xInterval,yInterval,grijs)
|
||||||
|
drawBlock(map,xInterval,yInterval,blauw)
|
||||||
|
|
||||||
|
screen:blit(player.x+1,player.y+1,Player)
|
||||||
|
screen:drawLine(x-5, y, x+5, y, wit)
|
||||||
|
screen:drawLine(x, y-5, x, y+5, wit)
|
||||||
|
|
||||||
|
pad = Controls.read()
|
||||||
|
|
||||||
|
dx = pad:analogX()
|
||||||
|
if math.abs(dx) > 32 then
|
||||||
|
x = x + dx / deler
|
||||||
|
end
|
||||||
|
|
||||||
|
dy = pad:analogY()
|
||||||
|
if math.abs(dy) > 32 then
|
||||||
|
y = y + dy / deler
|
||||||
|
end
|
||||||
|
|
||||||
|
if x<0 then
|
||||||
|
x=0
|
||||||
|
end
|
||||||
|
|
||||||
|
if y<0 then
|
||||||
|
y=0
|
||||||
|
end
|
||||||
|
|
||||||
|
if x>=table.getn(map[1])*xInterval then
|
||||||
|
x=table.getn(map[1])*xInterval-1
|
||||||
|
end
|
||||||
|
|
||||||
|
if y>=table.getn(map)*yInterval then
|
||||||
|
y=table.getn(map)*yInterval-1
|
||||||
|
end
|
||||||
|
|
||||||
|
local mapx=math.floor(x/xInterval)+1
|
||||||
|
local mapy=math.floor(y/yInterval)+1
|
||||||
|
|
||||||
|
if pad~=oldpad then
|
||||||
|
if pad:cross() then
|
||||||
|
orderMove=true
|
||||||
|
end
|
||||||
|
|
||||||
|
if pad:square() then
|
||||||
|
if map[mapy][mapx]==0 then
|
||||||
|
map[mapy][mapx]=1
|
||||||
|
elseif map[mapy][mapx]==1 then
|
||||||
|
map[mapy][mapx]=0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if pad:l() then
|
||||||
|
deler=deler*2
|
||||||
|
end
|
||||||
|
|
||||||
|
if pad:r() then
|
||||||
|
deler=deler/2
|
||||||
|
end
|
||||||
|
|
||||||
|
if pad:start() then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
oldpad=pad
|
||||||
|
|
||||||
|
if orderMove==true then
|
||||||
|
player.path=CalcPath(CalcMoves(map, math.floor(player.x/xInterval)+1, math.floor(player.y/yInterval)+1, mapx, mapy))
|
||||||
|
if player.path==nil then
|
||||||
|
orderMove=false
|
||||||
|
end
|
||||||
|
if player.path~=nil then
|
||||||
|
player.pathLength=table.getn(player.path)
|
||||||
|
player.cur=1
|
||||||
|
player.xmove=(player.path[player.cur].x*xInterval)-xInterval
|
||||||
|
player.ymove=(player.path[player.cur].y*yInterval)-yInterval
|
||||||
|
orderMove=false
|
||||||
|
player.move=true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Movement
|
||||||
|
if player.move==true then
|
||||||
|
if player.xmove>player.x then
|
||||||
|
player.x=player.x+player.speed
|
||||||
|
elseif player.xmove<player.x then
|
||||||
|
player.x=player.x-player.speed
|
||||||
|
end
|
||||||
|
if player.ymove>player.y then
|
||||||
|
player.y=player.y+player.speed
|
||||||
|
elseif player.ymove<player.y then
|
||||||
|
player.y=player.y-player.speed
|
||||||
|
end
|
||||||
|
|
||||||
|
if player.y==player.ymove and player.x==player.xmove and player.cur<player.pathLength then
|
||||||
|
player.cur=player.cur+1
|
||||||
|
player.xmove=(player.path[player.cur].x*xInterval)-xInterval
|
||||||
|
player.ymove=(player.path[player.cur].y*yInterval)-yInterval
|
||||||
|
end
|
||||||
|
if player.y==player.ymove and player.x==player.xmove and player.cur>=player.pathLength then
|
||||||
|
player.move=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
screen:print(0,264,"A* algorithm for LUA - Ported by Altair 2006",wit)
|
||||||
|
screen.waitVblankStart()
|
||||||
|
screen:flip()
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue