1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function table.empty(tab)
	for k, v in pairs(tab) do
		return false
	end
	return true
end
function FindPath(fx,fy,tx,ty)
	function Map(x,y)
		if tile(x,y,"walkable") then return 0 end
		return 1
	end
	if Map(fx,fy) == 1 or Map(tx,ty) == 1 then
		return nil, "The start or the goal is not walkable"
	end
	local Node = {}
	local sizex = map("xsize")+1
	local sizey = map("ysize")+1
	local curbase = {x = fx,y = fy}
	local openlist = {{x = fx,y = fy}}
	local G_Cost = {}
	local H_Cost = {}
	local function Euclidean(fx,fy,tx,ty)
		return math.sqrt((fx-tx)^2 + (fy-ty)^2)
	end
	local function Manhattan(fx,fy,tx,ty)
		return math.abs(fx-tx) + math.abs(fy-ty)
	end
	function CreateNodeConfig(x,y,open)
		if not Node[x] then Node[x] = {} end
		if not Node[x][y] then
			if open == nil then open = false end
			Node[x][y] = {
				Open = open,
				Closed = false,
				G = 0,
				H = Euclidean(x,y,tx,ty),
				parent = {}
			}
		end
	end
	CreateNodeConfig(fx,fy,1)
	local function FixedPath()
		local i = {x = tx,y = ty}
		local path = {}
		while Node[i.x][i.y].parent.x and Node[i.x][i.y].parent.y do
			local Details = {
				x = i.x,
				y = i.y,
				G = Node[i.x][i.y].G,
				H = Node[i.x][i.y].H
			}
			table.insert(path,Details)
			i = Node[i.x][i.y].parent
		end
		return path, #path, -1
	end
	while not table.empty(openlist) do
		local lH = nil -- Lowest F node
		local lHID = nil
		for k, v in pairs(openlist) do
			if not lH or Node[v.x][v.y].H < Node[lH.x][lH.y].H then
				lH = v
				lHID = k
			end
		end
		Node[lH.x][lH.y].Closed = true
		Node[lH.x][lH.y].Open = false
		openlist[lHID] = nil
		curbase = lH
		if curbase.x == tx and curbase.y == ty then
			return FixedPath()
		end
		local NearNodes = {}
		local function CheckNode(x,y)
			CreateNodeConfig(x,y)
			if not Node[x][y].Closed and Map(x,y) == 0 then
				table.insert(NearNodes,{x = x,y = y})
			end
		end
		CheckNode(curbase.x,curbase.y+1); CheckNode(curbase.x+1,curbase.y)
		CheckNode(curbase.x,curbase.y-1); CheckNode(curbase.x-1,curbase.y)
		if Map(curbase.x+1,curbase.y) == 0 and Map(curbase.x,curbase.y+1) == 0 then
			CheckNode(curbase.x+1,curbase.y+1)
		end
		if Map(curbase.x+1,curbase.y) == 0 and Map(curbase.x,curbase.y-1)== 0 then
			CheckNode(curbase.x+1,curbase.y-1)
		end
		if Map(curbase.x-1,curbase.y) == 0 and Map(curbase.x,curbase.y+1) == 0 then
			CheckNode(curbase.x-1,curbase.y+1)
		end
		if Map(curbase.x-1,curbase.y) == 0 and Map(curbase.x,curbase.y-1) == 0 then
			CheckNode(curbase.x-1,curbase.y-1)
		end
		function AddNode(k)
			if not NearNodes[k] then
				return nil
			end
			local v = NearNodes[k]
			local score = Node[curbase.x][curbase.y].G + Euclidean(curbase.x,curbase.y,v.x,v.y)
			if not Node[v.x][v.y].Open then
				local pos = #openlist+1
				openlist[pos] = {x = v.x,y = v.y}
				Node[v.x][v.y].Open = pos
				Node[v.x][v.y].parent = curbase
				Node[v.x][v.y].G = score
			elseif score <= Node[v.x][v.y].G then
				Node[v.x][v.y].parent = curbase
				Node[v.x][v.y].G = score
			end
		end
		AddNode(1); AddNode(2); AddNode(3); AddNode(4)
		AddNode(5); AddNode(6); AddNode(7); AddNode(8)
	end
	return nil, "Couldn't find the path"
end