Trying to get smallest number

I have a quite specific problem. I am making an A* algorithm, and one of the parts of that algorithm is to choose which tile to go next. For this, I use Manhattan method to determine the cost, aka how much tiles I would need to go from that position to finish. Then I just have to get smallest cost.

First thing I had in mind is to use math.min(UpCost, DownCost, RightCost, LeftCost) to determine where to go, and it worked fine. However, recently I added walls, and the method I implemented them, is just to remove the walls from the list of nodes. The result was simple: Part sometime could not have a specific neighbor, and because of that Up/Down/Right/Left Costs would become nil and because of that, math.min() refuses to work now.

I first tried to use lists, but sadly math.min() does not seem to work with lists… I tried to add additional if statements that if neighbor == nil, the cost would be extremely high. But this did not work too. So I am interested if there are any other methods I could determine the smallest number, or maybe a way to edit math.min() depending on the Costs.

Here is my code as of now:

local start = workspace.Nodes.Start
local finish = workspace.Nodes.Finish

local Nodes = workspace.Nodes:GetChildren()
local OpenList = {}
local ClosedList = {}
local Path = {}
local Neighbors = {}

script.Parent.MouseClick:Connect(function()
	table.insert(OpenList, start)
	while #OpenList > 0 do
		for i, part in pairs(Nodes) do
			part.SurfaceGui.IndicatorX.Text = math.abs(part.Position.X / 8)
			part.SurfaceGui.IndicatorZ.Text = math.abs(part.Position.Z / 8)
			if part:GetAttribute("Occupied") == true then
				table.remove(Nodes, table.find(Nodes, part))
			end
		end 

		for i, center in pairs(OpenList) do

			local UpNeighbor
			local DownNeighbor
			local RightNeighbor
			local LeftNeighbor

			local UpCost
			local DownCost
			local RightCost
			local LeftCost

			for i, n in pairs(Nodes) do
				if math.abs(n.Position.X / 8) == math.abs(center.Position.X / 8) and math.abs(n.Position.Z / 8) == math.abs(center.Position.Z / 8) + 1 then
					UpNeighbor = n
					UpCost = math.abs((finish.Position.X / 8) - (UpNeighbor.Position.X) / 8) + math.abs((finish.Position.Z / 8) - (UpNeighbor.Position.Z) / 8)
					table.insert(Neighbors, UpNeighbor)
							
				elseif math.abs(n.Position.X / 8) == math.abs(center.Position.X / 8) and math.abs(n.Position.Z / 8) == math.abs(center.Position.Z / 8) - 1  then
					DownNeighbor = n
					DownCost = math.abs((finish.Position.X / 8) - (DownNeighbor.Position.X) / 8) + math.abs((finish.Position.Z / 8) - (DownNeighbor.Position.Z) / 8)
					table.insert(Neighbors, DownNeighbor)
				elseif math.abs(n.Position.Z / 8) == math.abs(center.Position.Z / 8) and math.abs(n.Position.X / 8) == math.abs(center.Position.X / 8) + 1 then
					RightNeighbor = n
					RightCost = math.abs((finish.Position.X / 8) - (RightNeighbor.Position.X) / 8) + math.abs((finish.Position.Z / 8) - (RightNeighbor.Position.Z) / 8)
					table.insert(Neighbors, RightNeighbor)
				elseif math.abs(n.Position.Z / 8) == math.abs(center.Position.Z / 8) and math.abs(n.Position.X / 8) == math.abs(center.Position.X / 8) - 1 then
					LeftNeighbor = n
					LeftCost = math.abs((finish.Position.X / 8) - (LeftNeighbor.Position.X) / 8) + math.abs((finish.Position.Z / 8) - (LeftNeighbor.Position.Z) / 8)
					table.insert(Neighbors, LeftNeighbor)
				end	
			end
			
			print(Neighbors)

			local upcoming = math.min(UpCost, DownCost, LeftCost, RightCost)
			if upcoming == UpCost then
				table.remove(OpenList, 1)
				table.insert(Path, center)
				Neighbors = {}
				wait(0.1)
				table.insert(OpenList, UpNeighbor)
				if UpNeighbor == finish then
					table.insert(Path, finish)
					print("Path Found")
					print(Path)
					for i, v in pairs(Path) do
						v.BrickColor = BrickColor.new("Bright green")
						wait(0.5)
					end
				end
			elseif upcoming == DownCost then
				table.remove(OpenList, 1)
				table.insert(Path, center)
				Neighbors = {}
				wait(0.1)
				table.insert(OpenList, DownNeighbor)
				if DownNeighbor == finish then
					print("Path Found")
					table.insert(Path, finish)
					print(Path)
					for i, v in pairs(Path) do
						v.BrickColor = BrickColor.new("Bright green")
						wait(0.5)
					end
				end
			elseif upcoming == RightCost then
				table.remove(OpenList, 1)
				table.insert(Path, center)
				Neighbors = {}
				wait(0.1)
				table.insert(OpenList, RightNeighbor)
				if RightNeighbor == finish then
					print("Path Found")
					table.insert(Path, finish)
					print(Path)
					for i, v in pairs(Path) do
						v.BrickColor = BrickColor.new("Bright green")
						wait(0.5)
					end
				end
			elseif upcoming == LeftCost then
				table.remove(OpenList, 1)
				table.insert(Path, center)
				Neighbors = {}
				wait(0.1)
				table.insert(OpenList, LeftNeighbor)
				if LeftNeighbor == finish then
					print("Path Found")
					table.insert(Path, finish)
					print(Path)
					for i, v in pairs(Path) do
						v.BrickColor = BrickColor.new("Bright green")
						wait(0.5)
					end
				end
			end
		end
		wait(1)
	end
end)

You can make your own min function like this:

function min(...: number): number
	local foundMinimum = math.huge
	local numbers = {...}
	
	for _, v in numbers do
		if v >= foundMinimum then
			continue
		end
		
		foundMinimum = v
	end
	
	return foundMinimum
end

min(10, 8, 6, 4, 2, nil) -- Output: 2

You can actually use it on lists

local a = {5, 6, 9, 12, 1, 29, 4}
print(math.min(a))

That will error, but you can use the unpack() function which turns a list of items into a tuple

local a = {5, 6, 9, 12, 1, 29, 4}
print(math.min(unpack(a)))

That returns the min. Note though that unpacking does take some linear time to complete.

1 Like

Oh god thank you man! So funny to sometimes discover new methods

1 Like

Yeah it worked but now it seems my algorithm is stuck in an infinite loop changing from 1 tile to another. I will try to fix that

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.