days 13,14,15
This commit is contained in:
parent
97a068bfc3
commit
cccd9976df
4 changed files with 400 additions and 0 deletions
176
13/13.go
Normal file
176
13/13.go
Normal file
|
@ -0,0 +1,176 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type firewall struct {
|
||||
pos int
|
||||
size int
|
||||
current int
|
||||
up bool
|
||||
}
|
||||
|
||||
// cat input | go run 13.go
|
||||
|
||||
func main() {
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
var fwdata = make(map[int]firewall)
|
||||
|
||||
for scanner.Scan() {
|
||||
|
||||
s := strings.Split(scanner.Text(), ": ")
|
||||
pos, _ := strconv.Atoi(s[0])
|
||||
size, _ := strconv.Atoi(s[1])
|
||||
fwdata[pos] = firewall{pos, size - 1, 0, true}
|
||||
}
|
||||
|
||||
fmt.Println(RunFirewall(fwdata, 0))
|
||||
// We only need to do this once with RunFirewallFast
|
||||
fwdata = ResetHash(fwdata)
|
||||
|
||||
start := time.Now()
|
||||
|
||||
fmt.Println(FindDelay(fwdata))
|
||||
|
||||
t := time.Now()
|
||||
elapsed := t.Sub(start)
|
||||
fmt.Println(elapsed)
|
||||
|
||||
}
|
||||
|
||||
func ResetHash(fw map[int]firewall) map[int]firewall {
|
||||
for k, v := range fw {
|
||||
v.current = 0
|
||||
fw[k] = v
|
||||
}
|
||||
return fw
|
||||
}
|
||||
|
||||
func FindDelay(fw map[int]firewall) int {
|
||||
|
||||
// Work out the final position.
|
||||
var keys []int
|
||||
for k := range fw {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Ints(keys)
|
||||
endpos := keys[len(keys)-1]
|
||||
|
||||
// Using an array instead of hashmap drops from 300ms to 125 on my machine for my solution (3.96 million delay)
|
||||
var t []int
|
||||
for x := 0; x <= endpos; x++ {
|
||||
t = append(t, (fw[x].size * 2))
|
||||
}
|
||||
|
||||
Loop:
|
||||
for i := 0; ; i++ {
|
||||
// You can see earlier, slower (~300ms) version of this inner loop as a function below. This brings it down to ~100ms.
|
||||
for j := i; j <= i+endpos; j++ {
|
||||
p := t[j-i]
|
||||
if p != 0 && j%p == 0 {
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// slower hashmap version
|
||||
/*
|
||||
for i := 0; ; i++ {
|
||||
_, caught := RunFirewallFast(fw, i, endpos)
|
||||
if !caught {
|
||||
fmt.Println(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Well, the obvious solution is incredibly slow, and we don't need
|
||||
// to resolve the full 'caught' number, so we can make this dramatically faster.
|
||||
// It took less time to rewrite this than to run the result using RunFirewall...
|
||||
func RunFirewallFast(fw map[int]firewall, delay int, endpos int) (int, bool) {
|
||||
for j := delay; j <= delay+endpos; j++ {
|
||||
a, exists := fw[j-delay]
|
||||
if exists {
|
||||
interval := a.size * 2
|
||||
if j%interval == 0 {
|
||||
return 0, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func RunFirewall(fw map[int]firewall, delay int) (int, bool) {
|
||||
caught := 0
|
||||
caughtBool := false
|
||||
|
||||
var keys []int
|
||||
for k := range fw {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
endpos := keys[len(keys)-1]
|
||||
mypos := -1
|
||||
|
||||
for i := 0; ; i++ {
|
||||
|
||||
// Start moving after the delay
|
||||
if i >= delay {
|
||||
mypos++
|
||||
}
|
||||
|
||||
// Have we been caught?
|
||||
_, exists := fw[mypos]
|
||||
if exists && mypos >= 0 && fw[mypos].current == 0 {
|
||||
caught = caught + (fw[mypos].pos * (fw[mypos].size + 1))
|
||||
fmt.Println("Caught", mypos, caught, i, delay)
|
||||
caughtBool = true
|
||||
// Skip further rounds if we're just looking for the delay
|
||||
if delay > 0 {
|
||||
return 0, true
|
||||
}
|
||||
}
|
||||
|
||||
// End!
|
||||
if mypos == endpos {
|
||||
break
|
||||
}
|
||||
|
||||
// Move scanners for this round
|
||||
for _, k := range keys {
|
||||
c := fw[k]
|
||||
|
||||
if c.current == c.size {
|
||||
c.up = false
|
||||
}
|
||||
if c.current == 0 {
|
||||
c.up = true
|
||||
}
|
||||
|
||||
if c.up {
|
||||
c.current++
|
||||
} else {
|
||||
c.current--
|
||||
}
|
||||
|
||||
fw[k] = c
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return caught, caughtBool
|
||||
|
||||
}
|
36
13/13_test.go
Normal file
36
13/13_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var test = map[int]firewall{
|
||||
0: {0, 2, 0, true},
|
||||
1: {1, 1, 0, true},
|
||||
4: {4, 3, 0, true},
|
||||
6: {6, 3, 0, true},
|
||||
}
|
||||
|
||||
func TestFindDelay(t *testing.T) {
|
||||
test = ResetHash(test)
|
||||
v := FindDelay(test)
|
||||
if v != 10 {
|
||||
t.Error(
|
||||
"For", test,
|
||||
"expected 10",
|
||||
"got", v,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunFirewall(t *testing.T) {
|
||||
test = ResetHash(test)
|
||||
v, _ := RunFirewall(test, 0)
|
||||
if v != 24 {
|
||||
t.Error(
|
||||
"For", test,
|
||||
"expected 24",
|
||||
"got", v,
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue