Depends if this is instance-based or using UI elements
Assuming instances:
- Identify the basic characteristics of each cell. I’d also probably mark them down by name or attribute numbers 1-#cells starting at top right and cycling down to the right corner.
- it would be wise to simultaneously mark down the type of cell this is, probably a tag (AddTag())
- Know the starting and end cells. In this case, its cell at the start of the 4th and end of the 4th rows.
Things that MUST be true:
- All cells must be tagged “Straight” or “Corner”.
- All cells are instances here, and their name is an integer 1-#rows*15
- Cell orientation 0,0,0 means a straight cell is vertical [|], and 0,180,0 means a straight cell is horizontal [-].
- Note this can be adjusted as you wish, but this must be known for my calculations.
- Cell orientation 0,0,0 means a corner cell is in the shape [┗]. Cell orientation 0,180,0 means corner cell is in the shape [┒]
- Note this can be adjusted as you wish, but this must be known for my calculations.
local Cells = {}
for _, Cell in something:GetChildren() do
Cells[tonumber(Cell.Name)] = Cell
end
Great, so now we have all the information we will need. A final reference that will streamline this process is knowing the possible routes of each cell.
- I.e. straight cells travel straight vertical, corners can hit SideA and the side adjacent to it right or left
Now, it doesn’t really matter what rotation the parts are at when the puzzle starts, because they can be rotated 4x each regardless. To save some time, we will handle vertical lines individually because they only have 2x possible pathways.
local StartCell = Cells[15*3 + 1] -- just to show where i got the key 45 from, row 4 position 1]
local Solution = {} -- we will store solutions by {IndexOfCellOnBoard, OrientationThatIsTrue}
if StartCell:HasTag("Straight") then
Solution[1] = {46, Vector3.yAxis*180)} -- must be horizontal, at cell 46. (yAxis = Vector3.new(0,1,0)*180 = our desired orientation
elseif StartCell:HasTag("Corner") then -- could also be else, but for readability
Solution[1] = {46, math.random(1,2) == 1 and Vector3.yAxis*90 or Vector3.yAxis*180}
end
So in this segment above, we can see that we are making the 1st solution known. After all, this is necessary for us to be able to make the next remaining steps. If the start is a corner, the orientation can be 2 different solutions.
We never addressed the other requirement; an endpoint. We don’t KNOW when the endcell will be reached, but it will be at most rows15 cells away. So, we will assign 10e3 (1000) because we just need a number higher than rows15, and its easy to write/remember
local EndCell = Cells[15*4] -- end cell
if EndCell:HasTag("Straight") then
Solution[10e3] = {46, Vector3.yAxis*180} -- must be horizontal, at cell 60. (yAxis = Vector3.new(0,1,0)*180 = our desired orientation
elseif EndCell:HasTag("Corner") then -- could also be else, but for readability
Solution[10e3] = {46, math.random(1,2) == 1 and Vector3.yAxis*-90 or Vector3.zero}
end
Now, the hard part. We can manipulate a path in many ways, but the most important part is knowing when to stop. We already know the endpoint, so we will mark ‘Solved’ when our puzzle is at Cells 59, 45, or 75 [The 3 neighboring cells to cell 60]. However, it can only be solved if the endpoint is aligned with the cell aswell.
First we need a way to find neighbors of a cell. I won’t explain much but its purely mathematical, finding if top/bottom/left/right exist and inserting in a table.
local Solve = function()
local Batch = 0
local Neighbors = function(index)
local neighbors = {}
local rows = math.ceil(15*7 / 15)
if (index - 1) % 15~= 0 then -- if index -1 is a different row, its not a neighbor
table.insert(neighbors, index - 1)
end
if index % 15~= 0 and index + 1 <= 15*7 then -- if index +1 is a different row, then its not a neighbor
table.insert(neighbors, index + 1)
end
if index - 15 > 0 then -- also need to make sure that the index Exists in a row below, like at spot 1 there is no spot 0
table.insert(neighbors, index - 15)
end
if index + 15 <= 15*7 then -- same for maximums
table.insert(neighbors, index + 15)
end
return neighbors
end
Okay, so we now have a function to identify neighbors, we will just need some more work to apply it;
local totalCells = 15 * 7
local Last = {46, Solution[1][2]} -- index + orientation
local Solved = false
repeat
local lastIndex = Last[1]
-- check if at the end
local nearEnd = Neighbors(60)
if table.find(nearEnd, lastIndex) then
Solved = true
break
end
-- search neighbors of Last
local possibleNeighbors = Neighbors(lastIndex)
local foundNext = false
for _, i in possibleNeighbors do
local cell = Cells[i]
if not cell then continue end
-- decide next orientation
local DesiredOrientation
if cell:HasTag("Straight") then
-- continue straight if same column or row
if i == lastIndex + 15 or i == lastIndex - 15 then
DesiredOrientation = Vector3.new(0,0,0) -- vertical
else
DesiredOrientation = Vector3.new(0,180,0) -- horizontal
end
elseif cell:HasTag("Corner") then
-- pick one of two turns arbitrarily for now
DesiredOrientation = math.random(1,2) == 1 and Vector3.new(0,90,0) or Vector3.new(0,270,0)
end
-- store solution
table.insert(Solution, {i, DesiredOrientation})
Last = {i, DesiredOrientation}
foundNext = true
break
end
if not foundNext then
break
end
Batch += 1
if Batch % 5 == 0 then task.wait() end
until Solved
end
Okay, so now the solutions table is filled. From here on out, you might want to continuously loop and see if a parts orientation matches a solution, then color it green etc.
May have some issues, let me know [UNTESTED]
Let me know about any questions.