cem 0.1.3 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/cem.gemspec +5 -3
  4. data/examples/aoc2018/.gitignore +2 -0
  5. data/examples/aoc2018/day1.rb +13 -0
  6. data/examples/aoc2018/day10.rb +61 -0
  7. data/examples/aoc2018/day11.rb +66 -0
  8. data/examples/aoc2018/day12.rb +61 -0
  9. data/examples/aoc2018/day13.rb +167 -0
  10. data/examples/aoc2018/day14.rb +31 -0
  11. data/examples/aoc2018/day14_2.rb +71 -0
  12. data/examples/aoc2018/day15.rb +271 -0
  13. data/examples/aoc2018/day16.rb +158 -0
  14. data/examples/aoc2018/day17.rb +203 -0
  15. data/examples/aoc2018/day18.rb +113 -0
  16. data/examples/aoc2018/day18_rspec.rb +131 -0
  17. data/examples/aoc2018/day19.rb +145 -0
  18. data/examples/aoc2018/day1_part2.rb +30 -0
  19. data/examples/aoc2018/day2.rb +20 -0
  20. data/examples/aoc2018/day20.rb +103 -0
  21. data/examples/aoc2018/day21.rb +158 -0
  22. data/examples/aoc2018/day21_v2.rb +137 -0
  23. data/examples/aoc2018/day21_v3.rb +157 -0
  24. data/examples/aoc2018/day21_v4.rb +141 -0
  25. data/examples/aoc2018/day22.rb +212 -0
  26. data/examples/aoc2018/day23.rb +148 -0
  27. data/examples/aoc2018/day24.rb +156 -0
  28. data/examples/aoc2018/day25.rb +52 -0
  29. data/examples/aoc2018/day2_2.rb +27 -0
  30. data/examples/aoc2018/day3.rb +71 -0
  31. data/examples/aoc2018/day4.rb +46 -0
  32. data/examples/aoc2018/day5.rb +23 -0
  33. data/examples/aoc2018/day5_part2.rb +29 -0
  34. data/examples/aoc2018/day6.rb +53 -0
  35. data/examples/aoc2018/day7.rb +110 -0
  36. data/examples/aoc2018/day8.rb +39 -0
  37. data/examples/aoc2018/day8_part2.rb +65 -0
  38. data/examples/aoc2018/day9.rb +51 -0
  39. data/examples/aoc2018/day9_circular.rb +125 -0
  40. data/examples/aoc2018/inputs/day10_input.txt +395 -0
  41. data/examples/aoc2018/inputs/day11_input.txt +1 -0
  42. data/examples/aoc2018/inputs/day12_input.txt +34 -0
  43. data/examples/aoc2018/inputs/day12_input2.txt +16 -0
  44. data/examples/aoc2018/inputs/day13_input.txt +150 -0
  45. data/examples/aoc2018/inputs/day13_test.txt +6 -0
  46. data/examples/aoc2018/inputs/day14_input.txt +1 -0
  47. data/examples/aoc2018/inputs/day15_input.txt +32 -0
  48. data/examples/aoc2018/inputs/day15_input10.txt +32 -0
  49. data/examples/aoc2018/inputs/day15_input11.txt +32 -0
  50. data/examples/aoc2018/inputs/day15_input12.txt +32 -0
  51. data/examples/aoc2018/inputs/day15_input13.txt +32 -0
  52. data/examples/aoc2018/inputs/day15_input14.txt +32 -0
  53. data/examples/aoc2018/inputs/day15_input2.txt +7 -0
  54. data/examples/aoc2018/inputs/day15_input3.txt +9 -0
  55. data/examples/aoc2018/inputs/day15_input4.txt +7 -0
  56. data/examples/aoc2018/inputs/day15_input5.txt +7 -0
  57. data/examples/aoc2018/inputs/day15_input6.txt +7 -0
  58. data/examples/aoc2018/inputs/day15_input7.txt +7 -0
  59. data/examples/aoc2018/inputs/day15_input8.txt +5 -0
  60. data/examples/aoc2018/inputs/day15_input9.txt +7 -0
  61. data/examples/aoc2018/inputs/day15_test.txt +9 -0
  62. data/examples/aoc2018/inputs/day16_input.txt +3865 -0
  63. data/examples/aoc2018/inputs/day17_input.txt +2229 -0
  64. data/examples/aoc2018/inputs/day17_input_test.txt +8 -0
  65. data/examples/aoc2018/inputs/day18_input.txt +50 -0
  66. data/examples/aoc2018/inputs/day18_test.txt +10 -0
  67. data/examples/aoc2018/inputs/day19_input.txt +48 -0
  68. data/examples/aoc2018/inputs/day1_input.txt +955 -0
  69. data/examples/aoc2018/inputs/day20_input.txt +1 -0
  70. data/examples/aoc2018/inputs/day21_input.txt +32 -0
  71. data/examples/aoc2018/inputs/day22_input.txt +2 -0
  72. data/examples/aoc2018/inputs/day23_input.txt +1000 -0
  73. data/examples/aoc2018/inputs/day23_input2.txt +9 -0
  74. data/examples/aoc2018/inputs/day24_input.txt +24 -0
  75. data/examples/aoc2018/inputs/day25_input.txt +1483 -0
  76. data/examples/aoc2018/inputs/day2_input.txt +250 -0
  77. data/examples/aoc2018/inputs/day3_input.txt +1233 -0
  78. data/examples/aoc2018/inputs/day4_input.txt +1140 -0
  79. data/examples/aoc2018/inputs/day5_input.txt +1 -0
  80. data/examples/aoc2018/inputs/day6_input.txt +50 -0
  81. data/examples/aoc2018/inputs/day7_input.txt +101 -0
  82. data/examples/aoc2018/inputs/day8_input.txt +1 -0
  83. data/examples/aoc2018/inputs/day9_input.txt +1 -0
  84. data/lib/cem/ccommon.rb +67 -12
  85. data/lib/cem/cflame/popen.rb +89 -0
  86. data/lib/cem/cflame.rb +2 -0
  87. data/lib/cem/cruzzles.rb +198 -50
  88. data/lib/cem/version.rb +1 -1
  89. data/lib/cem.rb +0 -6
  90. metadata +91 -11
@@ -0,0 +1,137 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/21 part 1 and part 2
3
+ #
4
+ # Does not use any 'cem' functions
5
+ #
6
+ # Using Lambdas instead of interpreting each command.
7
+ #
8
+ require 'set'
9
+
10
+ lines = File.readlines("inputs/day21_input.txt", chomp: true)
11
+
12
+ commandQueue = []
13
+
14
+ @reg = [0,0,0,0,0,0]
15
+ @s = Set.new
16
+ @last = nil
17
+
18
+ ip = nil
19
+ lines.each { |line|
20
+
21
+ if line =~ /^#ip ([+-]?\d+)$/
22
+ ip = $1.to_i
23
+ end
24
+
25
+ if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
26
+ verb = $1
27
+ v1 = $2.to_i
28
+ v2 = $3.to_i
29
+ v3 = $4.to_i
30
+
31
+ commandQueue << case verb
32
+
33
+ when "addr"
34
+ # addr (add @register) stores into @register C the result of adding @register A and @register B.
35
+ Proc.new { @reg[v3] = @reg[v1] + @reg[v2] }
36
+
37
+ when "addi"
38
+ # addi (add immediate) stores into @register C the result of adding @register A and value B.
39
+ Proc.new { @reg[v3] = @reg[v1] + v2 }
40
+
41
+ when "mulr"
42
+ # mulr (multiply @register) stores into @register C the result of multiplying @register A and @register B.
43
+ Proc.new { @reg[v3] = @reg[v1] * @reg[v2] }
44
+
45
+ when "muli"
46
+ # muli (multiply immediate) stores into @register C the result of multiplying @register A and value B.
47
+ Proc.new { @reg[v3] = @reg[v1] * v2 }
48
+
49
+ when "banr"
50
+ # banr (bitwise AND @register) stores into @register C the result of the bitwise AND of @register A and @register B.
51
+ Proc.new { @reg[v3] = @reg[v1] & @reg[v2] }
52
+
53
+ when "bani"
54
+ # bani (bitwise AND immediate) stores into @register C the result of the bitwise AND of @register A and value B.
55
+ Proc.new { @reg[v3] = @reg[v1] & v2 }
56
+
57
+ when "borr"
58
+ # borr (bitwise OR @register) stores into @register C the result of the bitwise OR of @register A and @register B.
59
+ Proc.new { @reg[v3] = @reg[v1] | @reg[v2] }
60
+
61
+ when "bori"
62
+ # bori (bitwise OR immediate) stores into @register C the result of the bitwise OR of @register A and value B.
63
+ Proc.new { @reg[v3] = @reg[v1] | v2 }
64
+
65
+ when "setr"
66
+ # setr (set @register) copies the contents of @register A into @register C. (Input B is ignored.)
67
+ Proc.new { @reg[v3] = @reg[v1] }
68
+
69
+ when "seti"
70
+ # seti (set immediate) stores value A into @register C. (Input B is ignored.)
71
+ Proc.new { @reg[v3] = v1 }
72
+
73
+ when "gtir"
74
+ # gtir (greater-than immediate/@register) sets @register C to 1 if value A is greater than @register B. Otherwise, @register C is set to 0.
75
+ Proc.new { @reg[v3] = v1 > @reg[v2] ? 1 : 0 }
76
+
77
+ when "gtri"
78
+ # gtri (greater-than @register/immediate) sets @register C to 1 if @register A is greater than value B. Otherwise, @register C is set to 0.
79
+ Proc.new { @reg[v3] = @reg[v1] > v2 ? 1 : 0 }
80
+
81
+ when "gtrr"
82
+ # gtrr (greater-than @register/@register) sets @register C to 1 if @register A is greater than @register B. Otherwise, @register C is set to 0.
83
+ Proc.new { @reg[v3] = @reg[v1] > @reg[v2] ? 1 : 0 }
84
+
85
+ when "eqir"
86
+ # eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
87
+ Proc.new { @reg[v3] = v1 == @reg[v2] ? 1 : 0 }
88
+
89
+ when "eqri"
90
+ # eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
91
+ Proc.new { @reg[v3] = @reg[v1] == v2 ? 1 : 0 }
92
+
93
+
94
+ when "eqrr"
95
+ # eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
96
+ Proc.new { @reg[v3] = @reg[v1] == @reg[v2] ? 1 : 0
97
+
98
+ if v2 == 0
99
+ if @s.size == 0
100
+ puts "Part 1: #{@reg[v1]}"
101
+ end
102
+
103
+ puts "#{@s.size.to_s.rjust(10)} - #{@reg[v1]}" if @s.size % 64 == 0
104
+
105
+ if @s.include?(@reg[v1])
106
+ puts "Part 2: #{@last}"
107
+ exit
108
+ end
109
+ @s.add @reg[v1]
110
+ @last = @reg[v1]
111
+ end
112
+ }
113
+
114
+ else
115
+ puts "error" # raise "Error"
116
+ end
117
+
118
+ end
119
+ }
120
+
121
+ ipp = 0
122
+ iteration = 0
123
+
124
+ while ipp >= 0 && ipp < commandQueue.size
125
+
126
+ @reg[ip] = ipp
127
+ commandQueue[ipp].call()
128
+ ipp = @reg[ip]
129
+ ipp += 1
130
+
131
+ #puts iteration.to_s.rjust(13) + " " + command.inspect.ljust(40) + " " + reg.inspect if iteration % (1024*1024) == 0
132
+ #iteration += 1
133
+
134
+ end
135
+
136
+ puts @reg.inspect
137
+ puts @reg[0]
@@ -0,0 +1,157 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/21 part 1 and part 2
3
+ #
4
+ # Does not use any 'cem' functions
5
+ #
6
+ # Version 3: Put everything into a single Proc (did not help much)
7
+ #
8
+ require 'set'
9
+
10
+ lines = File.readlines("inputs/day21_input.txt", chomp: true)
11
+
12
+ commandQueue = []
13
+
14
+ @reg = [0,0,0,0,0,0]
15
+ @s = Set.new
16
+ @last = nil
17
+
18
+ def command(verb, v1, v2, v3)
19
+
20
+ case verb
21
+ when "addr"
22
+ # addr (add @register) stores into @register C the result of adding @register A and @register B.
23
+ " @reg[#{v3}] = @reg[#{v1}] + @reg[#{v2}] "
24
+
25
+ when "addi"
26
+ # addi (add immediate) stores into @register C the result of adding @register A and value B.
27
+ " @reg[#{v3}] = @reg[#{v1}] + #{v2} "
28
+
29
+ when "mulr"
30
+ # mulr (multiply @register) stores into @register C the result of multiplying @register A and @register B.
31
+ " @reg[#{v3}] = @reg[#{v1}] * @reg[#{v2}] "
32
+
33
+ when "muli"
34
+ # muli (multiply immediate) stores into @register C the result of multiplying @register A and value B.
35
+ " @reg[#{v3}] = @reg[#{v1}] * #{v2} "
36
+
37
+ when "banr"
38
+ # banr (bitwise AND @register) stores into @register C the result of the bitwise AND of @register A and @register B.
39
+ " @reg[#{v3}] = @reg[#{v1}] & @reg[#{v2}] "
40
+
41
+ when "bani"
42
+ # bani (bitwise AND immediate) stores into @register C the result of the bitwise AND of @register A and value B.
43
+ " @reg[#{v3}] = @reg[#{v1}] & #{v2} "
44
+
45
+ when "borr"
46
+ # borr (bitwise OR @register) stores into @register C the result of the bitwise OR of @register A and @register B.
47
+ " @reg[#{v3}] = @reg[#{v1}] | @reg[#{v2}] "
48
+
49
+ when "bori"
50
+ # bori (bitwise OR immediate) stores into @register C the result of the bitwise OR of @register A and value B.
51
+ " @reg[#{v3}] = @reg[#{v1}] | #{v2} "
52
+
53
+ when "setr"
54
+ # setr (set @register) copies the contents of @register A into @register C. (Input B is ignored.)
55
+ " @reg[#{v3}] = @reg[#{v1}] "
56
+
57
+ when "seti"
58
+ # seti (set immediate) stores value A into @register C. (Input B is ignored.)
59
+ " @reg[#{v3}] = #{v1} "
60
+
61
+ when "gtir"
62
+ # gtir (greater-than immediate/@register) sets @register C to 1 if value A is greater than @register B. Otherwise, @register C is set to 0.
63
+ " @reg[#{v3}] = #{v1} > @reg[#{v2}] ? 1 : 0 "
64
+
65
+ when "gtri"
66
+ # gtri (greater-than @register/immediate) sets @register C to 1 if @register A is greater than value B. Otherwise, @register C is set to 0.
67
+ " @reg[#{v3}] = @reg[#{v1}] > #{v2} ? 1 : 0 "
68
+
69
+ when "gtrr"
70
+ # gtrr (greater-than @register/@register) sets @register C to 1 if @register A is greater than @register B. Otherwise, @register C is set to 0.
71
+ " @reg[#{v3}] = @reg[#{v1}] > @reg[#{v2}] ? 1 : 0 "
72
+
73
+ when "eqir"
74
+ # eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
75
+ " @reg[#{v3}] = #{v1} == @reg[#{v2}] ? 1 : 0 "
76
+
77
+ when "eqri"
78
+ # eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
79
+ " @reg[#{v3}] = @reg[#{v1}] == #{v2} ? 1 : 0 "
80
+
81
+ when "eqrr"
82
+ # eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
83
+ " @reg[#{v3}] = @reg[#{v1}] == @reg[#{v2}] ? 1 : 0
84
+
85
+ if #{v2} == 0
86
+ if @s.size == 0
87
+ puts \"Part 1: \#{@reg[#{v1}]}\"
88
+ end
89
+
90
+ puts \"\#{@s.size.to_s.rjust(10)} - \#{@reg[#{v1}]}\" if @s.size % 64 == 0
91
+
92
+ if @s.include?(@reg[#{v1}])
93
+ puts \"Part 2: \#{@last}\"
94
+ exit
95
+ end
96
+ @s.add @reg[#{v1}]
97
+ @last = @reg[#{v1}]
98
+ end
99
+ "
100
+
101
+ else
102
+ puts "error" # raise "Error"
103
+ end
104
+ end
105
+
106
+
107
+
108
+ ipid = 0
109
+ ip = nil
110
+ lines.each { |line|
111
+
112
+ if line =~ /^#ip ([+-]?\d+)$/
113
+ ip = $1.to_i
114
+ end
115
+
116
+ if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
117
+ verb = $1
118
+ v1 = $2.to_i
119
+ v2 = $3.to_i
120
+ v3 = $4.to_i
121
+
122
+ p = command(verb, v1, v2, v3)
123
+
124
+ puts p
125
+
126
+ commandQueue << p
127
+
128
+ end
129
+ }
130
+
131
+ ippMax = commandQueue.size
132
+
133
+ commandQueue = "case ipp\n" + commandQueue.each_with_index.map { |v, i|
134
+ "when #{i}\n #{v}\n"
135
+ }.join("\n") + "\nend"
136
+
137
+ ipp = 0
138
+ iteration = 0
139
+
140
+ puts commandQueue
141
+ commandQueue = eval("
142
+ while #ipp >= 0 && ipp < ippMax
143
+
144
+ @reg[ip] = ipp
145
+
146
+ #{commandQueue}
147
+
148
+ ipp = @reg[ip]
149
+ ipp += 1
150
+
151
+ end")
152
+
153
+ #{commandQueue} }")
154
+
155
+
156
+ puts @reg.inspect
157
+ puts @reg[0]
@@ -0,0 +1,141 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/21 part 1 and part 2
3
+ #
4
+ # Does not use any 'cem' functions
5
+ #
6
+ # Rev 4: Replace the register array access with local variables => Double speed up.
7
+ #
8
+ require 'cem'
9
+ require 'set'
10
+
11
+ lines = File.readlines("inputs/day21_input.txt", chomp: true)
12
+
13
+ commandQueue = []
14
+
15
+ r0 = r1 = r2 = r3 = r4 = r5 = 0
16
+ @s = Set.new
17
+ @last = nil
18
+
19
+ def command(verb, v1, v2, v3)
20
+
21
+ case verb
22
+ when "addr"
23
+ # addr (add @register) stores into @register C the result of adding @register A and @register B.
24
+ " r#{v3} = r#{v1} + r#{v2} "
25
+
26
+ when "addi"
27
+ # addi (add immediate) stores into @register C the result of adding @register A and value B.
28
+ " r#{v3} = r#{v1} + #{v2} "
29
+
30
+ when "mulr"
31
+ # mulr (multiply @register) stores into @register C the result of multiplying @register A and @register B.
32
+ " r#{v3} = r#{v1} * r#{v2} "
33
+
34
+ when "muli"
35
+ # muli (multiply immediate) stores into @register C the result of multiplying @register A and value B.
36
+ " r#{v3} = r#{v1} * #{v2} "
37
+
38
+ when "banr"
39
+ # banr (bitwise AND @register) stores into @register C the result of the bitwise AND of @register A and @register B.
40
+ " r#{v3} = r#{v1} & r#{v2} "
41
+
42
+ when "bani"
43
+ # bani (bitwise AND immediate) stores into @register C the result of the bitwise AND of @register A and value B.
44
+ " r#{v3} = r#{v1} & #{v2} "
45
+
46
+ when "borr"
47
+ # borr (bitwise OR @register) stores into @register C the result of the bitwise OR of @register A and @register B.
48
+ " r#{v3} = r#{v1} | r#{v2} "
49
+
50
+ when "bori"
51
+ # bori (bitwise OR immediate) stores into @register C the result of the bitwise OR of @register A and value B.
52
+ " r#{v3} = r#{v1} | #{v2} "
53
+
54
+ when "setr"
55
+ # setr (set @register) copies the contents of @register A into @register C. (Input B is ignored.)
56
+ " r#{v3} = r#{v1} "
57
+
58
+ when "seti"
59
+ # seti (set immediate) stores value A into @register C. (Input B is ignored.)
60
+ " r#{v3} = #{v1} "
61
+
62
+ when "gtir"
63
+ # gtir (greater-than immediate/@register) sets @register C to 1 if value A is greater than @register B. Otherwise, @register C is set to 0.
64
+ " r#{v3} = #{v1} > r#{v2} ? 1 : 0 "
65
+
66
+ when "gtri"
67
+ # gtri (greater-than @register/immediate) sets @register C to 1 if @register A is greater than value B. Otherwise, @register C is set to 0.
68
+ " r#{v3} = r#{v1} > #{v2} ? 1 : 0 "
69
+
70
+ when "gtrr"
71
+ # gtrr (greater-than @register/@register) sets @register C to 1 if @register A is greater than @register B. Otherwise, @register C is set to 0.
72
+ " r#{v3} = r#{v1} > r#{v2} ? 1 : 0 "
73
+
74
+ when "eqir"
75
+ # eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
76
+ " r#{v3} = #{v1} == r#{v2} ? 1 : 0 "
77
+
78
+ when "eqri"
79
+ # eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
80
+ " r#{v3} = r#{v1} == #{v2} ? 1 : 0 "
81
+
82
+ when "eqrr"
83
+ # eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
84
+ " r#{v3} = r#{v1} == r#{v2} ? 1 : 0
85
+
86
+ if #{v2} == 0
87
+ if @s.size == 0
88
+ puts \"Part 1: \#{r#{v1}}\"
89
+ end
90
+
91
+ puts \"\#{@s.size.to_s.rjust(10)} - \#{r#{v1}}\" if @s.size % 64 == 0
92
+
93
+ if @s.include?(r#{v1})
94
+ puts \"Part 2: \#{@last}\"
95
+ exit
96
+ end
97
+ @s.add r#{v1}
98
+ @last = r#{v1}
99
+ end
100
+ "
101
+ else
102
+ puts "error" # raise "Error"
103
+ end
104
+ end
105
+
106
+
107
+ ip = nil
108
+ lines.each { |line|
109
+
110
+ if line =~ /^#ip ([+-]?\d+)$/
111
+ ip = $1.to_i
112
+ end
113
+
114
+ if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
115
+ verb = $1
116
+ v1 = $2.to_i
117
+ v2 = $3.to_i
118
+ v3 = $4.to_i
119
+
120
+ commandQueue << command(verb, v1, v2, v3)
121
+ end
122
+ }
123
+
124
+ ndigits = commandQueue.size.digits.size
125
+
126
+ commandQueue = <<~EOS
127
+ while
128
+
129
+ case r#{ip}
130
+ #{commandQueue.each_with_index.map { |v, i| "when #{i.to_s.rjust(ndigits)} then #{v}"}.join("\n")}
131
+ else
132
+ raise
133
+ end
134
+
135
+ r#{ip} += 1
136
+
137
+ end
138
+ EOS
139
+
140
+ puts commandQueue
141
+ eval(commandQueue)
@@ -0,0 +1,212 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/22 part 1 and 2
3
+ #
4
+ # Demonstrates some use of Grid and Point2D
5
+ #
6
+ # Why this was hard: Did not read spec precisely!
7
+
8
+ require 'set'
9
+ require 'cem'
10
+
11
+ EXTRAX = 10
12
+ EXTRAY = 10
13
+
14
+ verbose = false
15
+
16
+ lines = File.readlines("inputs/day22_input.txt", chomp: true)
17
+
18
+ depth = nil
19
+ target = nil
20
+
21
+ lines.each { |line|
22
+
23
+ if line =~ /^depth: ([+-]?\d+)$/
24
+ depth = $1.to_i
25
+ end
26
+
27
+ if line =~ /^target: ([+-]?\d+),([+-]?\d+)$/
28
+ target = Point2D.new($1.to_i, $2.to_i)
29
+ end
30
+ }
31
+
32
+ @depth = depth
33
+ @target = target
34
+
35
+ def erode(x)
36
+ return (x + @depth) % 20183
37
+ end
38
+
39
+ grid = Grid.new(target.x + EXTRAX + 1, target.y + EXTRAY + 1)
40
+ grid[0,0] = 0
41
+
42
+ (1..target.x + EXTRAX).each { |x|
43
+ grid[0,x] = erode(x * 16807)
44
+ }
45
+ (1..target.y + EXTRAY).each { |y|
46
+ grid[y,0] = erode(y * 48271)
47
+ }
48
+
49
+ (1..target.y + EXTRAY).each { |y|
50
+ (1..target.x + EXTRAX).each { |x|
51
+ if target.x == x && target.y == y
52
+ grid[y,x] = erode(0)
53
+ else
54
+ grid[y,x] = erode(grid[y-1,x] * grid[y,x-1])
55
+ end
56
+ }
57
+ }
58
+
59
+ puts "Part 1: #{grid[0..target.y, 0..target.x].flatten.sum { |g| g % 3 }}"
60
+
61
+ if verbose
62
+ grid[0..target.y, 0..target.x].each { |y|
63
+ y.each { |c|
64
+ case c % 3
65
+ when 0
66
+ print '.'
67
+ when 1
68
+ print '='
69
+ when 2
70
+ print '|'
71
+ end
72
+ }
73
+ puts
74
+ }
75
+ end
76
+
77
+ #
78
+ # Part 2
79
+ #
80
+
81
+ neighter = 0
82
+ torch = 1
83
+ gear = 2
84
+
85
+ toolGrid = [0,1,2,4].map { |t| Grid.new(target.x + EXTRAX + 1, target.y + EXTRAY + 1, -1)}
86
+
87
+ toolGrid[torch][0,0] = 0
88
+
89
+ define_method :toChar do |p|
90
+ case grid[p] % 3
91
+ when 0
92
+ '.'
93
+ when 1
94
+ '='
95
+ when 2
96
+ '|'
97
+ end
98
+ end
99
+
100
+ define_method :supportedTools do |p|
101
+
102
+ case grid[p] % 3
103
+ when 0 # rocky
104
+ [gear, torch]
105
+ when 1 # wet
106
+ [neighter, gear]
107
+ when 2 # narrow
108
+ [neighter, torch]
109
+ else
110
+ raise
111
+ end
112
+ end
113
+
114
+ q = [[Point2D.new(0,0), torch]]
115
+ while q.size > 0
116
+
117
+ p, tool = q.shift
118
+
119
+ #puts "#{p.inspect} - #{tool} - #{toolGrid[tool][p]} - #{supportedTools(p)}"
120
+
121
+ sTools = supportedTools(p)
122
+ otherTools = ([0,1,2] - [tool]) & supportedTools(p)
123
+
124
+ otherTools.each { |t|
125
+ raise if t == tool
126
+ raise if !sTools.any? { |t2| t == t2 }
127
+ }
128
+
129
+ raise if toolGrid[tool][p] == -1
130
+
131
+ otherTools.each { |other|
132
+ if (toolGrid[other][p] == -1) || toolGrid[tool][p] + 7 < toolGrid[other][p]
133
+ toolGrid[other][p] = toolGrid[tool][p] + 7
134
+ q << [p, other]
135
+ end
136
+ }
137
+
138
+ grid.nsew_index(p).each { |p2|
139
+ # puts "#{p2.inspect} is adjacent to #{p} and supports the following tools #{supportedTools(p2)}"
140
+
141
+ if supportedTools(p2).include?(tool) && (toolGrid[tool][p2] == -1 || toolGrid[tool][p] + 1 < toolGrid[tool][p2])
142
+ toolGrid[tool][p2] = toolGrid[tool][p] + 1
143
+ q << [p2, tool]
144
+ end
145
+ }
146
+
147
+ q.sort_by! { |n|
148
+ p, tool = n
149
+ toolGrid[tool][p]
150
+ }
151
+
152
+ end
153
+
154
+ puts "Part 2: #{[toolGrid[torch][target], toolGrid[gear][target] + 7].min}"
155
+
156
+ if 0 == 1
157
+ (0..target.y + EXTRAY).each { |y|
158
+ (0..target.x + EXTRAX).each { |x|
159
+
160
+ case grid[y,x] % 3
161
+
162
+ when 0
163
+ print '.'
164
+ when 1
165
+ print '='
166
+ when 2
167
+ print '|'
168
+
169
+ end
170
+
171
+ print (toolGrid[torch][y,x].to_s + "," + toolGrid[neighter][y,x].to_s + "," +toolGrid[gear][y,x].to_s).rjust(8)
172
+ }
173
+ puts ""
174
+ } if DEBUG
175
+
176
+ reversePath = [[target, toolGrid[torch][target], torch]]
177
+ p = target
178
+ curTool = torch
179
+ while !(p.x == 0 && p.y == 0)
180
+
181
+ moves = grid.nsew_index(p).select { |p2| supportedTools(p2).include?(curTool) }.map { |p2| [p2, toolGrid[curTool][p2], curTool]} +
182
+ (supportedTools(p) - [curTool]).map { |t| [p, toolGrid[t][p], t, :toolChange] }
183
+
184
+ p moves
185
+ bestMove = moves.min_by { |x| x[1] }
186
+
187
+ reversePath.unshift bestMove
188
+
189
+ # puts p.inspect
190
+
191
+ p = bestMove[0]
192
+ curTool = bestMove[2]
193
+ end
194
+
195
+ reversePath.each { |x|
196
+ puts "[#{x[0].x}, #{x[0].y}, #{x[2]}] #{toChar(x[0])} #{x[1]} #{x.size > 3 ? x[3] : ""}"
197
+ }
198
+ end
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+