code.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. type op byte
  9. const (
  10. addx op = iota
  11. noop
  12. )
  13. type command struct {
  14. instruction op
  15. value int
  16. }
  17. func readInput(file *os.File) []command {
  18. scanner := bufio.NewScanner(file)
  19. var commands []command
  20. for scanner.Scan() {
  21. line := scanner.Text()
  22. if line == "" {
  23. continue
  24. }
  25. var current command
  26. if line[0] == 'n' {
  27. current.instruction = noop
  28. } else {
  29. current.instruction = addx
  30. n, err := fmt.Sscanf(line, "addx %d", &current.value)
  31. if n != 1 || err != nil {
  32. log.Fatal("Can't parse input:", err, line)
  33. }
  34. }
  35. commands = append(commands, current)
  36. }
  37. return commands
  38. }
  39. func part1(commands []command) int {
  40. cycles := 0
  41. currentLimit := 20
  42. absoluteLimit := 221
  43. result := 0
  44. x := 1
  45. for i := range commands {
  46. if cycles > absoluteLimit {
  47. break
  48. }
  49. if commands[i].instruction == noop {
  50. cycles++
  51. } else {
  52. cycles += 2
  53. if cycles >= currentLimit {
  54. result += currentLimit * x
  55. currentLimit += 40
  56. }
  57. x += commands[i].value
  58. }
  59. }
  60. return result
  61. }
  62. func inSprite(pixel int, sprite int) bool {
  63. return pixel >= sprite-1 && pixel <= sprite+1
  64. }
  65. func putMark(pixel int, sprite int) byte {
  66. if inSprite(pixel, sprite) {
  67. return '#'
  68. }
  69. return '.'
  70. }
  71. func part2(commands []command) [][]byte {
  72. sprite := 1
  73. currentLimit := 40
  74. period := 40
  75. absoluteLimit := 220
  76. cycles := 0
  77. totalCycles := 0
  78. var result [][]byte
  79. currentRow := make([]byte, period)
  80. for i := range commands {
  81. if cycles > absoluteLimit {
  82. break
  83. }
  84. end := 1
  85. if commands[i].instruction == addx {
  86. end++
  87. }
  88. for j := 0; j < end; j++ {
  89. cycles++
  90. currentRow[cycles-1] = putMark(cycles-1, sprite)
  91. if cycles == currentLimit {
  92. result = append(result, currentRow)
  93. totalCycles += cycles
  94. currentRow = make([]byte, period)
  95. cycles = 0
  96. }
  97. }
  98. if commands[i].instruction == addx {
  99. sprite += commands[i].value
  100. }
  101. }
  102. return result
  103. }
  104. func printScreen(screen [][]byte) {
  105. for i := range screen {
  106. fmt.Println(string(screen[i]))
  107. }
  108. }
  109. func main() {
  110. if len(os.Args) < 2 {
  111. log.Fatal("You need to specify a file!")
  112. }
  113. filePath := os.Args[1]
  114. file, err := os.Open(filePath)
  115. if err != nil {
  116. log.Fatalf("Failed to open %s!\n", filePath)
  117. }
  118. commands := readInput(file)
  119. fmt.Println("Part1:", part1(commands))
  120. fmt.Println("Part2:")
  121. printScreen(part2(commands))
  122. }