Possibly done?

This commit is contained in:
Brian Buller 2016-12-24 23:58:45 -06:00
parent 556faf20d1
commit a01a65364c

View File

@ -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