Experimental/ModuleScripts/Grids.lua

188 lines
5.1 KiB
Lua
Raw Normal View History

2024-12-11 05:31:59 +00:00
-- by Sovereignty 12/11/2024
local random = Random.new()
export type Grid<e> = {
Nodes: { {
Entry: e,
Index: number,
RowX: number,
RowZ: number,
} },
Index: (index: number) -> (GridMethods),
FirstRow: (x: number) -> (number),
LastRow: (x: number) -> (number),
}
type GridMethods = {
GetNext: (self: {}) -> (number?),
GetPrev: (self: {}) -> (number?),
GetForward: (self: {}) -> (number?),
GetBackward: (self: {}) -> (number?),
}
local function new<e>(rowX: number, rowZ: number, perGridEntryCallback: (index: number, x: number, z: number) -> (e)): Grid<e>
local grid = {}
for zIndex = 1, rowZ do
for xIndex = 1, rowX do
local thisPadIndex = (zIndex - 1) * rowX + xIndex
table.insert(grid, {
Entry = perGridEntryCallback(thisPadIndex, xIndex, zIndex),
Index = thisPadIndex,
RowX = xIndex,
RowZ = zIndex
})
end
end
local entryIndex: number
local function getNextEntry(): number?
local entryData = grid[entryIndex]
local xIndex: number = entryData.RowX
local zIndex: number = entryData.RowZ
if xIndex < rowX then
return (zIndex - 1) * rowX + (xIndex + 1)
end
return nil
end
local function getPrevEntry(): number?
local entryData = grid[entryIndex]
if entryData.Index == entryIndex then
local xIndex: number = entryData.RowX
local zIndex: number = entryData.RowZ
if xIndex > 1 then
return (zIndex - 1) * rowX + (xIndex - 1)
end
end
return nil
end
local function getForwardEntry(): number?
local entryData = grid[entryIndex]
if entryData.Index == entryIndex then
local xIndex: number = entryData.RowX
local zIndex: number = entryData.RowZ
if zIndex < rowZ then
return zIndex * rowX + xIndex
end
end
return nil
end
local function getBackwardEntry(): number?
local entryData = grid[entryIndex]
if entryData.Index == entryIndex then
local xIndex: number = entryData.RowX
local zIndex: number = entryData.RowZ
if zIndex > 1 then
return (zIndex - 2) * rowX + xIndex
end
end
return nil
end
local function firstRowX(entry: number): number
print((1 - 1) * rowX + entry)
return (1 - 1) * rowX + entry
end
local function lastRowX(entry: number): number
print((rowZ - 1) * rowX + entry)
return (rowZ - 1) * rowX + entry
end
local methods = {
GetNext = getNextEntry,
GetPrev = getPrevEntry,
GetForward = getForwardEntry,
GetBackward = getBackwardEntry
}
local function fromEntry(index: number): GridMethods
entryIndex = index
return methods
end
return {
Nodes = grid,
Index = fromEntry,
LastRow = lastRowX,
FirstRow = firstRowX
}
end
local function generateRandomPath<grid>(grid: grid & Grid<any>, startIndex: number, endIndex: number): { number }
local currentIndex = startIndex
local path = {currentIndex}
local visited = {}
visited[currentIndex] = true
while currentIndex ~= endIndex do
local directions = {}
local nextNode = grid.Index(currentIndex):GetNext()
local prevNode = grid.Index(currentIndex):GetPrev()
local forwardNode = grid.Index(currentIndex):GetForward()
if nextNode and not visited[nextNode] then
table.insert(directions, {node = nextNode, weight = 1.4})
end
if prevNode and not visited[prevNode] then
table.insert(directions, {node = prevNode, weight = 1.4})
end
if forwardNode and not visited[forwardNode] then
table.insert(directions, {node = forwardNode, weight = 1.2})
end
for i, direction in ipairs(directions) do
local distance = math.abs(direction.node - endIndex)
direction.weight = direction.weight / (distance + 1)
end
if #directions > 0 then
local totalWeight = 0
for _, direction in ipairs(directions) do
totalWeight = totalWeight + direction.weight
end
local rand = random:NextNumber(0, totalWeight)
local accumulatedWeight = 0
local selectedNode
for _, direction in ipairs(directions) do
accumulatedWeight = accumulatedWeight + direction.weight
if rand <= accumulatedWeight then
selectedNode = direction.node
break
end
end
currentIndex = selectedNode
table.insert(path, currentIndex)
visited[currentIndex] = true
else
break
end
end
return path
end
return {
new = new,
Path = generateRandomPath
}