Skip to content

Commit

Permalink
Merge pull request #732 from vaskoz/day313
Browse files Browse the repository at this point in the history
Day313
  • Loading branch information
vaskoz committed Oct 19, 2019
2 parents 3c7ed79 + f0ec21d commit 07abb73
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ problems from
* [Day 310](https://github.com/vaskoz/dailycodingproblem-go/issues/633)
* [Day 311](https://github.com/vaskoz/dailycodingproblem-go/issues/635)
* [Day 312](https://github.com/vaskoz/dailycodingproblem-go/issues/637)
* [Day 313](https://github.com/vaskoz/dailycodingproblem-go/issues/639)
* [Day 314](https://github.com/vaskoz/dailycodingproblem-go/issues/640)
* [Day 315](https://github.com/vaskoz/dailycodingproblem-go/issues/642)
* [Day 317](https://github.com/vaskoz/dailycodingproblem-go/issues/645)
Expand Down
89 changes: 89 additions & 0 deletions day313/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package day313

// MovesToUnlock returns the minimum number of moves to unlock a rotary
// lock avoid all dead ends.
// Returns -1 if it's not possible.
// Panics if the input data is inconsistent.
// Runs in O(N) or O(V+E) time since BFS is a linear algorithm.
func MovesToUnlock(start, target [3]int, deadEnds [][3]int) int {
if start == target {
return 0
}

for _, v := range start {
if v < 0 || v > 9 {
panic("start values must all be 0-9")
}
}

for _, v := range target {
if v < 0 || v > 9 {
panic("target values must all be 0-9")
}
}

graph := make([][][]int, 10)
for i := range graph {
graph[i] = make([][]int, 10)
for j := range graph[i] {
graph[i][j] = make([]int, 10)
}
}

for _, de := range deadEnds {
for _, v := range de {
if v < 0 || v > 9 {
panic("dead end values must all be 0-9")
}
}

x, y, z := de[0], de[1], de[2]
graph[x][y][z] = -1
}

bfs(graph, start)

return graph[target[0]][target[1]][target[2]] - 1
}

func bfs(g [][][]int, start [3]int) {
var q [][3]int

g[start[0]][start[1]][start[2]] = 1

q = append(q, start)

for len(q) != 0 {
var v [3]int
v, q = q[0], q[1:]
dist := g[v[0]][v[1]][v[2]]

for _, dir := range [][3]int{
{-1, 0, 0}, {0, -1, 0}, {0, 0, -1},
{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
} {
next := coord(v, dir)
x, y, z := next[0], next[1], next[2]

if g[x][y][z] == 0 {
g[x][y][z] = dist + 1

q = append(q, next)
}
}
}
}

func coord(start, direction [3]int) [3]int {
var result [3]int
for i := range result {
result[i] = start[i] + direction[i]
if result[i] > 9 {
result[i] = 0
} else if result[i] < 0 {
result[i] = 9
}
}

return result
}
89 changes: 89 additions & 0 deletions day313/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package day313

import "testing"

// nolint
var testcases = []struct {
start, target [3]int
deadEnds [][3]int
expected int
}{
{
[3]int{0, 0, 0},
[3]int{7, 1, 9},
[][3]int{{1, 1, 1}},
5,
},
{
[3]int{0, 0, 0},
[3]int{0, 0, 0},
[][3]int{{1, 1, 1}},
0,
},
{
[3]int{0, 0, 0},
[3]int{5, 5, 5},
[][3]int{{1, 0, 0}, {0, 1, 0}, {9, 0, 0}, {0, 9, 0}, {0, 0, 1}, {0, 0, 9}},
-1,
},
{
[3]int{0, 0, 0},
[3]int{5, 5, 5},
[][3]int{{0, 1, 0}, {9, 0, 0}, {0, 9, 0}, {0, 0, 1}, {0, 0, 9}},
15,
},
}

func TestMovesToUnlock(t *testing.T) {
t.Parallel()

for _, tc := range testcases {
if result := MovesToUnlock(tc.start, tc.target, tc.deadEnds); result != tc.expected {
t.Errorf("Expected %v, got %v", tc.expected, result)
}
}
}

func TestMovesToUnlockBadStartPanic(t *testing.T) {
t.Parallel()

defer func() {
if err := recover(); err == nil {
t.Errorf("Expected a panic for bad start coordinates")
}
}()

MovesToUnlock([3]int{-1, 10, 5}, [3]int{1, 1, 1}, [][3]int{})
}

func TestMovesToUnlockBadTargetPanic(t *testing.T) {
t.Parallel()

defer func() {
if err := recover(); err == nil {
t.Errorf("Expected a panic for bad target coordinates")
}
}()

MovesToUnlock([3]int{0, 0, 0}, [3]int{10, 1, 1}, [][3]int{})
}

func TestMovesToUnlockBadDeadEndPanic(t *testing.T) {
t.Parallel()

defer func() {
if err := recover(); err == nil {
t.Errorf("Expected a panic for bad dead end coordinates")
}
}()

MovesToUnlock([3]int{0, 0, 0}, [3]int{1, 1, 1}, [][3]int{{-1, 0, 0}})
}

func BenchmarkMovesToUnlock(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
MovesToUnlock(tc.start, tc.target, tc.deadEnds)
}
}
}
2 changes: 2 additions & 0 deletions day333/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package day333
// NOTE: This is not bidirectional.
type Knowing map[int]map[int]bool

// Knows is a O(1) method that answers if 'a' "knows" 'b'.
// This does not imply that 'b' "knows" 'a'.
func (k *Knowing) Knows(a, b int) bool {
if known, exists := (*k)[a]; exists {
return known[b]
Expand Down

0 comments on commit 07abb73

Please sign in to comment.