Possibly done?
This commit is contained in:
parent
556faf20d1
commit
a01a65364c
@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var shortestSolutionDist int
|
var shortestSolutionDist int
|
||||||
|
var pois []string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
playMode := aoc.ArgIsSet("-play")
|
playMode := aoc.ArgIsSet("-play")
|
||||||
@ -58,8 +59,8 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
shortestSolutionDist = -1
|
shortestSolutionDist = -1
|
||||||
m.PrintMaze()
|
m.PrintMaze()
|
||||||
m.StartSolve(0)
|
m.StartSolve()
|
||||||
fmt.Println("Shortest Solution: ", shortestSolutionDist)
|
//fmt.Println("Shortest Solution: ", shortestSolutionDist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +260,7 @@ func (p *Path) Append(c Coord) {
|
|||||||
p.coords = append(p.coords, c)
|
p.coords = append(p.coords, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Path) ContainsCoord(x, y int) bool {
|
func (p *Path) Contains(x, y int) bool {
|
||||||
for i := range p.coords {
|
for i := range p.coords {
|
||||||
if p.coords[i].is(x, y) {
|
if p.coords[i].is(x, y) {
|
||||||
return true
|
return true
|
||||||
@ -293,13 +294,23 @@ func CreateMaze(inp []string) *Maze {
|
|||||||
for y := range inp {
|
for y := range inp {
|
||||||
for x := range inp[y] {
|
for x := range inp[y] {
|
||||||
if inp[y][x] == '#' {
|
if inp[y][x] == '#' {
|
||||||
m.walls.Add(x, y, aoc.FillChar)
|
m.walls.Add(x, y, "#") //aoc.FillChar)
|
||||||
} else if inp[y][x] != '.' {
|
} else if inp[y][x] != '.' {
|
||||||
if inp[y][x] == '0' {
|
if inp[y][x] == '0' {
|
||||||
m.start = &Coord{x: x, y: y, label: "0"}
|
m.start = &Coord{x: x, y: y, label: "0"}
|
||||||
} else {
|
} else {
|
||||||
m.pois.Add(x, y, string(inp[y][x]))
|
m.pois.Add(x, y, string(inp[y][x]))
|
||||||
}
|
}
|
||||||
|
newOne := true
|
||||||
|
for pi := range pois {
|
||||||
|
if pois[pi] == string(inp[y][x]) {
|
||||||
|
newOne = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if newOne {
|
||||||
|
pois = append(pois, string(inp[y][x]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if x > m.w {
|
if x > m.w {
|
||||||
m.w = x
|
m.w = x
|
||||||
@ -346,167 +357,148 @@ func (m *Maze) PrintMaze() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartSolve kicks off the solve and returns the lowest number of steps, or an error
|
|
||||||
func (m *Maze) StartSolve(dist int) (int, error) {
|
|
||||||
numWorkers++
|
|
||||||
solved, d := m.Solve(m.start.x, m.start.y, 0)
|
|
||||||
dist += d
|
|
||||||
numWorkers--
|
|
||||||
if !solved {
|
|
||||||
return dist, errors.New("Couldn't solve maze. :(")
|
|
||||||
}
|
|
||||||
fmt.Println("Ended Solve (current workers:", numWorkers, "; current shortest:", shortestSolutionDist, ")")
|
|
||||||
if dist < shortestSolutionDist || shortestSolutionDist == -1 {
|
|
||||||
shortestSolutionDist = dist
|
|
||||||
}
|
|
||||||
return dist, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to build a set of all solutions from one poi to all others
|
|
||||||
// then find the shortest path that hits them all
|
|
||||||
func (m *Maze) Solve(x, y, dist int) (bool, int) {
|
|
||||||
wrkCoord := Coord{x: x, y: y, dist: dist}
|
|
||||||
if m.end == nil || m.end.is(x, y) {
|
|
||||||
// We found a point of interest! (or we're just starting)
|
|
||||||
|
|
||||||
// No end set. For each poi, we want to fork a new maze being solved
|
|
||||||
// with the end set to that poi, and that poi removed from the poi list
|
|
||||||
if len(m.pois.coords) == 0 {
|
|
||||||
// Unless there aren't any left, then we solved it
|
|
||||||
return true, dist
|
|
||||||
}
|
|
||||||
for i := range m.pois.coords {
|
|
||||||
endPoi := m.pois.coords[i]
|
|
||||||
// Copy the pois
|
|
||||||
newPois := make([]Coord, len(m.pois.coords))
|
|
||||||
copy(newPois, m.pois.coords)
|
|
||||||
// Then delete the endPoi from it
|
|
||||||
newPois = append(newPois[:i], newPois[i+1:]...)
|
|
||||||
// Create a new maze with start set to this point and end set to the first poi
|
|
||||||
newM := CopyMaze(m.walls, CreateCCFromCoordSlice(newPois))
|
|
||||||
newM.start = &wrkCoord
|
|
||||||
newM.end = &endPoi
|
|
||||||
newM.StartSolve(dist + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if m.testedPath.ContainsCoord(x, y) {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
// Figure out if there is a shorter path to this coordinate
|
|
||||||
if !m.walls.Contains(x-1, y) {
|
|
||||||
if t := m.testedPath.GetCoordAt(x-1, y); t != nil {
|
|
||||||
if t.dist+1 < wrkCoord.dist {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !m.walls.Contains(x+1, y) {
|
|
||||||
if t := m.testedPath.GetCoordAt(x+1, y); t != nil {
|
|
||||||
if t.dist+1 < wrkCoord.dist {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !m.walls.Contains(x, y-1) {
|
|
||||||
if t := m.testedPath.GetCoordAt(x, y-1); t != nil {
|
|
||||||
if t.dist+1 < wrkCoord.dist {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !m.walls.Contains(x, y+1) {
|
|
||||||
if t := m.testedPath.GetCoordAt(x, y+1); t != nil {
|
|
||||||
if t.dist+1 < wrkCoord.dist {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.testedPath.Append(wrkCoord)
|
|
||||||
shortest := -1
|
|
||||||
var foundSol bool
|
|
||||||
if m.testedPath.GetCoordAt(x-1, y) == nil && !m.walls.Contains(x-1, y) {
|
|
||||||
if sol, nDist := m.Solve(x-1, y, wrkCoord.dist+1); sol {
|
|
||||||
foundSol = true
|
|
||||||
if nDist < shortest || shortest == -1 {
|
|
||||||
shortest = nDist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if m.testedPath.GetCoordAt(x, y-1) == nil && !m.walls.Contains(x, y-1) {
|
|
||||||
if sol, nDist := m.Solve(x, y-1, wrkCoord.dist+1); sol {
|
|
||||||
foundSol = true
|
|
||||||
if nDist < shortest || shortest == -1 {
|
|
||||||
shortest = nDist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if m.testedPath.GetCoordAt(x+1, y) == nil && !m.walls.Contains(x+1, y) {
|
|
||||||
if sol, nDist := m.Solve(x+1, y, wrkCoord.dist+1); sol {
|
|
||||||
foundSol = true
|
|
||||||
if nDist < shortest || shortest == -1 {
|
|
||||||
shortest = nDist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if m.testedPath.GetCoordAt(x, y+1) == nil && !m.walls.Contains(x, y+1) {
|
|
||||||
if sol, nDist := m.Solve(x, y+1, wrkCoord.dist+1); sol {
|
|
||||||
foundSol = true
|
|
||||||
if nDist < shortest || shortest == -1 {
|
|
||||||
shortest = nDist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return foundSol, dist + shortest
|
|
||||||
}
|
|
||||||
|
|
||||||
var shortestPoiDist map[string]int
|
var shortestPoiDist map[string]int
|
||||||
|
|
||||||
// Pt2StartSolve finds the shortest distance between every poi and every other poi
|
// StartSolve finds the shortest distance between every poi and every other poi
|
||||||
func (m *Maze) Pt2StartSolve() {
|
// Then figures out the shortest one to hit them all
|
||||||
|
func (m *Maze) StartSolve() {
|
||||||
shortestPoiDist = make(map[string]int)
|
shortestPoiDist = make(map[string]int)
|
||||||
for _, i := range m.pois.coords {
|
for _, i := range m.pois.coords {
|
||||||
if gud, dist := m.GetShortestPath(m.start, i, 0); gud {
|
if dist, gud := m.GetShortestPath(m.start.x, m.start.y, i.x, i.y, 0, *new(Path)); gud {
|
||||||
shortestPoiDist[m.start.label+";"+i.label] = dist
|
shortestPoiDist[m.start.label+";"+i.label] = dist
|
||||||
}
|
}
|
||||||
for _, j := range m.pois.coords {
|
for _, j := range m.pois.coords {
|
||||||
if i.label != j.label {
|
if i.label != j.label {
|
||||||
fst, scd := i, j
|
fst, scd := i, j
|
||||||
if i[0] > j[0] {
|
if i.label[0] > j.label[0] {
|
||||||
fst, scd = j, i
|
fst, scd = j, i
|
||||||
}
|
}
|
||||||
if _, ok := shortestPoiDist[fst+";"+scd]; !ok {
|
if _, ok := shortestPoiDist[fst.label+";"+scd.label]; !ok {
|
||||||
if gud, dist := m.GetShortestPath(i, j, 0); gud {
|
if dist, gud := m.GetShortestPath(i.x, i.y, j.x, j.y, 0, *new(Path)); gud {
|
||||||
shortestPoiDist[fst+";"+scd] = dist
|
shortestPoiDist[fst.label+";"+scd.label] = dist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Find shortest path that hits them all
|
|
||||||
|
var poiString string
|
||||||
|
fmt.Println("pois", pois)
|
||||||
|
for i := range pois {
|
||||||
|
poiString += pois[i]
|
||||||
|
}
|
||||||
|
poiPerms := aoc.StringPermutations(poiString)
|
||||||
|
var wrk []string
|
||||||
|
for i := range poiPerms {
|
||||||
|
var found bool
|
||||||
|
for j := range wrk {
|
||||||
|
if wrk[j] == poiPerms[i] {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
wrk = append(wrk, poiPerms[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poiPerms = wrk
|
||||||
|
shortest := -1
|
||||||
|
var shortestPerm string
|
||||||
|
for _, perm := range poiPerms {
|
||||||
|
if perm[0] != '0' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var permTtl int
|
||||||
|
for i := range perm {
|
||||||
|
if i > 0 {
|
||||||
|
beg, end := string(perm[i-1]), string(perm[i])
|
||||||
|
if beg[0] > end[0] {
|
||||||
|
beg, end = end, beg
|
||||||
|
}
|
||||||
|
permTtl += shortestPoiDist[beg+";"+end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if permTtl < shortest || shortest == -1 {
|
||||||
|
shortestPerm = perm
|
||||||
|
shortest = permTtl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(shortestPerm, ": ", shortest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetShortestPath just finds the shortest path between two points
|
// GetShortestPath just finds the shortest path between two points
|
||||||
func (m *Maze) GetShortestPath(beg *Coord, end *Coord, dist int) (int, bool) {
|
func (m *Maze) GetShortestPath(begX, begY, endX, endY, dist int, path Path) (int, bool) {
|
||||||
// TODO: actually solve for shortest path
|
if begX == endX && begY == endY {
|
||||||
|
return dist, true
|
||||||
|
}
|
||||||
|
if path.Contains(begX, begY) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
|
||||||
|
|
||||||
/* Put on hold
|
|
||||||
// We're going to find the closest POI (straight-line) and solve to it
|
|
||||||
func (m *Maze) Solve(x, y, dist int) bool {
|
|
||||||
wrkCoord := Coord{x: x, y: y, dist: dist}
|
|
||||||
_ = wrkCoord
|
|
||||||
if m.end == nil || m.end.is(x, y) {
|
|
||||||
// We made it (or haven't started)! Do we have any more pois?
|
|
||||||
if len(m.pois.coords) == 0 {
|
|
||||||
// Nope, none left, we're done
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
m.end = m.FindClosestPoi()
|
// Figure out if there is a shorter path to this coordinate
|
||||||
|
if !m.walls.Contains(begX-1, begY) {
|
||||||
|
if t := path.GetCoordAt(begX-1, begY); t != nil {
|
||||||
|
if t.dist+1 < dist {
|
||||||
|
return 0, false
|
||||||
}
|
}
|
||||||
return false
|
}
|
||||||
|
}
|
||||||
|
if !m.walls.Contains(begX+1, begY) {
|
||||||
|
if t := path.GetCoordAt(begX+1, begY); t != nil {
|
||||||
|
if t.dist+1 < dist {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !m.walls.Contains(begX, begY-1) {
|
||||||
|
if t := path.GetCoordAt(begX, begY-1); t != nil {
|
||||||
|
if t.dist+1 < dist {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !m.walls.Contains(begX, begY+1) {
|
||||||
|
if t := path.GetCoordAt(begX, begY+1); t != nil {
|
||||||
|
if t.dist+1 < dist {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.Append(Coord{x: begX, y: begY, dist: dist})
|
||||||
|
shortest := -1
|
||||||
|
var foundSol bool
|
||||||
|
if path.GetCoordAt(begX-1, begY) == nil && !m.walls.Contains(begX-1, begY) {
|
||||||
|
if nDist, sol := m.GetShortestPath(begX-1, begY, endX, endY, dist+1, path); sol {
|
||||||
|
foundSol = true
|
||||||
|
if nDist < shortest || shortest == -1 {
|
||||||
|
shortest = nDist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if path.GetCoordAt(begX, begY-1) == nil && !m.walls.Contains(begX, begY-1) {
|
||||||
|
if nDist, sol := m.GetShortestPath(begX, begY-1, endX, endY, dist+1, path); sol {
|
||||||
|
foundSol = true
|
||||||
|
if nDist < shortest || shortest == -1 {
|
||||||
|
shortest = nDist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if path.GetCoordAt(begX+1, begY) == nil && !m.walls.Contains(begX+1, begY) {
|
||||||
|
if nDist, sol := m.GetShortestPath(begX+1, begY, endX, endY, dist+1, path); sol {
|
||||||
|
foundSol = true
|
||||||
|
if nDist < shortest || shortest == -1 {
|
||||||
|
shortest = nDist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if path.GetCoordAt(begX, begY+1) == nil && !m.walls.Contains(begX, begY+1) {
|
||||||
|
if nDist, sol := m.GetShortestPath(begX, begY+1, endX, endY, dist+1, path); sol {
|
||||||
|
foundSol = true
|
||||||
|
if nDist < shortest || shortest == -1 {
|
||||||
|
shortest = nDist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shortest, foundSol
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func (m *Maze) FindClosestPoi() *Coord {
|
func (m *Maze) FindClosestPoi() *Coord {
|
||||||
var shortestPoi Coord
|
var shortestPoi Coord
|
||||||
|
Loading…
Reference in New Issue
Block a user