Possibly done?
This commit is contained in:
parent
556faf20d1
commit
a01a65364c
@ -13,6 +13,7 @@ import (
|
||||
)
|
||||
|
||||
var shortestSolutionDist int
|
||||
var pois []string
|
||||
|
||||
func main() {
|
||||
playMode := aoc.ArgIsSet("-play")
|
||||
@ -58,8 +59,8 @@ func main() {
|
||||
} else {
|
||||
shortestSolutionDist = -1
|
||||
m.PrintMaze()
|
||||
m.StartSolve(0)
|
||||
fmt.Println("Shortest Solution: ", shortestSolutionDist)
|
||||
m.StartSolve()
|
||||
//fmt.Println("Shortest Solution: ", shortestSolutionDist)
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +260,7 @@ func (p *Path) Append(c Coord) {
|
||||
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 {
|
||||
if p.coords[i].is(x, y) {
|
||||
return true
|
||||
@ -293,13 +294,23 @@ func CreateMaze(inp []string) *Maze {
|
||||
for y := range inp {
|
||||
for x := range inp[y] {
|
||||
if inp[y][x] == '#' {
|
||||
m.walls.Add(x, y, aoc.FillChar)
|
||||
m.walls.Add(x, y, "#") //aoc.FillChar)
|
||||
} else if inp[y][x] != '.' {
|
||||
if inp[y][x] == '0' {
|
||||
m.start = &Coord{x: x, y: y, label: "0"}
|
||||
} else {
|
||||
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 {
|
||||
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
|
||||
|
||||
// Pt2StartSolve finds the shortest distance between every poi and every other poi
|
||||
func (m *Maze) Pt2StartSolve() {
|
||||
// StartSolve finds the shortest distance between every poi and every other poi
|
||||
// Then figures out the shortest one to hit them all
|
||||
func (m *Maze) StartSolve() {
|
||||
shortestPoiDist = make(map[string]int)
|
||||
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
|
||||
}
|
||||
for _, j := range m.pois.coords {
|
||||
if i.label != j.label {
|
||||
fst, scd := i, j
|
||||
if i[0] > j[0] {
|
||||
if i.label[0] > j.label[0] {
|
||||
fst, scd = j, i
|
||||
}
|
||||
if _, ok := shortestPoiDist[fst+";"+scd]; !ok {
|
||||
if gud, dist := m.GetShortestPath(i, j, 0); gud {
|
||||
shortestPoiDist[fst+";"+scd] = dist
|
||||
if _, ok := shortestPoiDist[fst.label+";"+scd.label]; !ok {
|
||||
if dist, gud := m.GetShortestPath(i.x, i.y, j.x, j.y, 0, *new(Path)); gud {
|
||||
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
|
||||
func (m *Maze) GetShortestPath(beg *Coord, end *Coord, dist int) (int, bool) {
|
||||
// TODO: actually solve for shortest path
|
||||
func (m *Maze) GetShortestPath(begX, begY, endX, endY, dist int, path Path) (int, bool) {
|
||||
if begX == endX && begY == endY {
|
||||
return dist, true
|
||||
}
|
||||
if path.Contains(begX, begY) {
|
||||
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 {
|
||||
var shortestPoi Coord
|
||||
|
Loading…
Reference in New Issue
Block a user