cem 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/examples/aoc2018/.gitignore +2 -0
  3. data/examples/aoc2018/day10.rb +61 -0
  4. data/examples/aoc2018/day11.rb +66 -0
  5. data/examples/aoc2018/day12.rb +61 -0
  6. data/examples/aoc2018/day13.rb +167 -0
  7. data/examples/aoc2018/day14.rb +31 -0
  8. data/examples/aoc2018/day14_2.rb +71 -0
  9. data/examples/aoc2018/day15.rb +271 -0
  10. data/examples/aoc2018/day16.rb +158 -0
  11. data/examples/aoc2018/day17.rb +203 -0
  12. data/examples/aoc2018/day18.rb +113 -0
  13. data/examples/aoc2018/day18_rspec.rb +131 -0
  14. data/examples/aoc2018/day19.rb +145 -0
  15. data/examples/aoc2018/day20.rb +103 -0
  16. data/examples/aoc2018/day21.rb +158 -0
  17. data/examples/aoc2018/day21_v2.rb +137 -0
  18. data/examples/aoc2018/day21_v3.rb +157 -0
  19. data/examples/aoc2018/day21_v4.rb +141 -0
  20. data/examples/aoc2018/day22.rb +212 -0
  21. data/examples/aoc2018/day23.rb +148 -0
  22. data/examples/aoc2018/day24.rb +156 -0
  23. data/examples/aoc2018/day25.rb +52 -0
  24. data/examples/aoc2018/day9.rb +51 -0
  25. data/examples/aoc2018/day9_circular.rb +125 -0
  26. data/examples/aoc2018/inputs/day10_input.txt +395 -0
  27. data/examples/aoc2018/inputs/day11_input.txt +1 -0
  28. data/examples/aoc2018/inputs/day12_input.txt +34 -0
  29. data/examples/aoc2018/inputs/day12_input2.txt +16 -0
  30. data/examples/aoc2018/inputs/day13_input.txt +150 -0
  31. data/examples/aoc2018/inputs/day13_test.txt +6 -0
  32. data/examples/aoc2018/inputs/day14_input.txt +1 -0
  33. data/examples/aoc2018/inputs/day15_input.txt +32 -0
  34. data/examples/aoc2018/inputs/day15_input10.txt +32 -0
  35. data/examples/aoc2018/inputs/day15_input11.txt +32 -0
  36. data/examples/aoc2018/inputs/day15_input12.txt +32 -0
  37. data/examples/aoc2018/inputs/day15_input13.txt +32 -0
  38. data/examples/aoc2018/inputs/day15_input14.txt +32 -0
  39. data/examples/aoc2018/inputs/day15_input2.txt +7 -0
  40. data/examples/aoc2018/inputs/day15_input3.txt +9 -0
  41. data/examples/aoc2018/inputs/day15_input4.txt +7 -0
  42. data/examples/aoc2018/inputs/day15_input5.txt +7 -0
  43. data/examples/aoc2018/inputs/day15_input6.txt +7 -0
  44. data/examples/aoc2018/inputs/day15_input7.txt +7 -0
  45. data/examples/aoc2018/inputs/day15_input8.txt +5 -0
  46. data/examples/aoc2018/inputs/day15_input9.txt +7 -0
  47. data/examples/aoc2018/inputs/day15_test.txt +9 -0
  48. data/examples/aoc2018/inputs/day16_input.txt +3865 -0
  49. data/examples/aoc2018/inputs/day17_input.txt +2229 -0
  50. data/examples/aoc2018/inputs/day17_input_test.txt +8 -0
  51. data/examples/aoc2018/inputs/day18_input.txt +50 -0
  52. data/examples/aoc2018/inputs/day18_test.txt +10 -0
  53. data/examples/aoc2018/inputs/day19_input.txt +48 -0
  54. data/examples/aoc2018/inputs/day20_input.txt +1 -0
  55. data/examples/aoc2018/inputs/day21_input.txt +32 -0
  56. data/examples/aoc2018/inputs/day22_input.txt +2 -0
  57. data/examples/aoc2018/inputs/day23_input.txt +1000 -0
  58. data/examples/aoc2018/inputs/day23_input2.txt +9 -0
  59. data/examples/aoc2018/inputs/day24_input.txt +24 -0
  60. data/examples/aoc2018/inputs/day25_input.txt +1483 -0
  61. data/examples/aoc2018/inputs/day9_input.txt +1 -0
  62. data/lib/cem.rb +0 -6
  63. data/lib/cem/ccommon.rb +45 -0
  64. data/lib/cem/cruzzles.rb +93 -38
  65. data/lib/cem/version.rb +1 -1
  66. metadata +62 -2
@@ -0,0 +1,113 @@
1
+
2
+ #
3
+ # https://adventofcode.com/2018/day/18 part 1 and 2
4
+ #
5
+ # Demonstrates Grid and Object#peql. For an rspec based variant see day18_rspec.rb
6
+ #
7
+
8
+ require 'cem'
9
+ require 'set'
10
+
11
+ def run(inputFilename, part1, debug)
12
+
13
+ lines = []
14
+ File.readlines(inputFilename, chomp: true).each { |line|
15
+ lines << line.rstrip
16
+ }
17
+
18
+ maxY = lines.size
19
+ maxX = lines[0].length
20
+
21
+ @m = Grid.new(maxX, maxY, '.')
22
+
23
+ @map = []
24
+ lines.each_with_index { |l, y|
25
+ result = []
26
+
27
+ l.chars.each_with_index { |c, x|
28
+ result << c
29
+ @m[y,x] = c
30
+ }
31
+ @map << result
32
+ }
33
+
34
+ puts "Initial State" if debug
35
+ puts @m if debug
36
+
37
+ intermediates = Set.new
38
+
39
+ startIteration = nil
40
+ periodicity = nil
41
+ tickResultCache = nil
42
+
43
+ # Read board
44
+ (1..1000000000).each { |i|
45
+
46
+ @m2 = @m.clone
47
+
48
+ @map.each_with_index { |l, y|
49
+
50
+ l.each_with_index { |c, x|
51
+
52
+ # puts "Adja: #{x} #{y}"
53
+ ajda = @m.adja_index(x,y)
54
+ case @m[y,x]
55
+ when '.'
56
+ @m2[y,x] = ajda.select { |p| @m[p] == '|' }.size >= 3 ? '|' : '.'
57
+ when '|'
58
+ @m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 3 ? '#' : '|'
59
+ when '#'
60
+ @m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 1 && ajda.select { |p| @m[p] == '|' }.size >= 1 ? '#' : '.'
61
+ end
62
+
63
+ puts "#{y} #{x} was #{@m[y,x]} is now #{@m2[y,x]}: #{ajda.inspect}" if debug
64
+
65
+ }
66
+ }
67
+
68
+ @m = @m2
69
+
70
+ if part1 && i == 10
71
+ puts "Part 1: Score after #{i} tick is #{@m.count('#') * @m.count('|')}" # if debug
72
+ break
73
+ end
74
+
75
+ puts @m if debug if debug
76
+ gets if debug
77
+
78
+ if !part1
79
+ tickResult = @m.to_a
80
+
81
+ if periodicity == nil && tickResultCache == tickResult
82
+ periodicity = i - startIteration
83
+ # puts periodicity
84
+ elsif periodicity
85
+ if ((1000000000 - i) % periodicity) == 0
86
+ break
87
+ end
88
+ end
89
+
90
+ if startIteration == nil && intermediates.include?(tickResult)
91
+ startIteration = i
92
+ tickResultCache = tickResult
93
+ elsif startIteration == nil
94
+ intermediates.add(tickResult)
95
+ end
96
+
97
+ end
98
+ }
99
+
100
+ @m.count('#') * @m.count('|')
101
+ end
102
+
103
+ debug = false
104
+
105
+ {
106
+ "inputs/day18_test.txt" => [1147, 0],
107
+ "inputs/day18_input.txt" => [589931, 222332],
108
+ }.each_pair { |k,v|
109
+
110
+ peql(run(k, true, debug), v[0], "Testing #{k.inspect} part 1")
111
+ peql(run(k, false, debug), v[1], "Testing #{k.inspect} part 2")
112
+
113
+ }
@@ -0,0 +1,131 @@
1
+
2
+ #
3
+ # https://adventofcode.com/2018/day/18 part 1 and 2
4
+ #
5
+ # Demonstrates Grid and Object#peql. For a variant without rspec see day18.rb
6
+ #
7
+
8
+ require 'cem'
9
+ require 'set'
10
+
11
+ def run(inputFilename, part1, debug)
12
+
13
+ lines = []
14
+ File.readlines(inputFilename, chomp: true).each { |line|
15
+ lines << line.rstrip
16
+ }
17
+
18
+ maxY = lines.size
19
+ maxX = lines[0].length
20
+
21
+ @m = Grid.new(maxX, maxY, '.')
22
+
23
+ @map = []
24
+ lines.each_with_index { |l, y|
25
+ result = []
26
+
27
+ l.chars.each_with_index { |c, x|
28
+ result << c
29
+ @m[y,x] = c
30
+ }
31
+ @map << result
32
+ }
33
+
34
+ puts "Initial State" if debug
35
+ puts @m if debug
36
+
37
+ intermediates = Set.new
38
+
39
+ startIteration = nil
40
+ periodicity = nil
41
+ tickResultCache = nil
42
+
43
+ # Read board
44
+ (1..1000000000).each { |i|
45
+
46
+ @m2 = @m.clone
47
+
48
+ @map.each_with_index { |l, y|
49
+
50
+ l.each_with_index { |c, x|
51
+
52
+ # puts "Adja: #{x} #{y}"
53
+ ajda = @m.adja_index(x,y)
54
+ case @m[y,x]
55
+ when '.'
56
+ @m2[y,x] = ajda.select { |p| @m[p] == '|' }.size >= 3 ? '|' : '.'
57
+ when '|'
58
+ @m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 3 ? '#' : '|'
59
+ when '#'
60
+ @m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 1 && ajda.select { |p| @m[p] == '|' }.size >= 1 ? '#' : '.'
61
+ end
62
+
63
+ puts "#{y} #{x} was #{@m[y,x]} is now #{@m2[y,x]}: #{ajda.inspect}" if debug
64
+
65
+ }
66
+ }
67
+
68
+ @m = @m2
69
+
70
+ if part1 && i == 10
71
+ puts "Part 1: Score after #{i} tick is #{@m.count('#') * @m.count('|')}" # if debug
72
+ break
73
+ end
74
+
75
+ puts @m if debug if debug
76
+ gets if debug
77
+
78
+ if !part1
79
+ tickResult = @m.to_a
80
+
81
+ if periodicity == nil && tickResultCache == tickResult
82
+ periodicity = i - startIteration
83
+ # puts periodicity
84
+ elsif periodicity
85
+ if ((1000000000 - i) % periodicity) == 0
86
+ break
87
+ end
88
+ end
89
+
90
+ if startIteration == nil && intermediates.include?(tickResult)
91
+ startIteration = i
92
+ tickResultCache = tickResult
93
+ elsif startIteration == nil
94
+ intermediates.add(tickResult)
95
+ end
96
+
97
+ end
98
+ }
99
+
100
+ @m.count('#') * @m.count('|')
101
+ end
102
+
103
+ debug = false
104
+
105
+ require 'rspec'
106
+
107
+ RSpec.configure do |config|
108
+ config.color = true # Use color in STDOUT
109
+ config.tty = true # Use color not only in STDOUT but also in pagers and files
110
+ config.formatter = :documentation
111
+ end
112
+
113
+ describe $__FILE__ do
114
+
115
+ {
116
+ "inputs/day18_test.txt" => [1147, 1],
117
+ "inputs/day18_input.txt" => [589931, 222332],
118
+ }.each_pair { |k,v|
119
+
120
+ it "testing #{k.inspect} part 1" do
121
+ expect(run(k, true, debug)).to eq(v[0])
122
+ end
123
+
124
+ it "testing #{k.inspect} part 2" do
125
+ expect(run(k, false, debug)).to eq(v[1])
126
+ end
127
+ }
128
+
129
+ end
130
+
131
+ RSpec::Core::Runner.run([$__FILE__])
@@ -0,0 +1,145 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/19 part 1 and 2
3
+ #
4
+
5
+ # My code was too slow to handle this problem, so this is really more analytical from observing the state of the machine and figuring out what it does.
6
+
7
+ shortcut = true
8
+ if shortcut
9
+
10
+ result = 0
11
+ (1..930).each { |i|
12
+ result += i if 930 % i == 0
13
+ }
14
+ puts "Part 1: #{result}"
15
+
16
+ result = 0
17
+ (1..10551330).each { |i|
18
+ result += i if 10551330 % i == 0
19
+ }
20
+ puts "Part 2: #{result}"
21
+ exit
22
+ end
23
+
24
+
25
+ [1,2].each { |part|
26
+
27
+ lines = File.readlines("inputs/day19_input.txt", chomp: true)
28
+
29
+ commandQueue = []
30
+
31
+ reg = [part - 1, 0, 0, 0, 0, 0]
32
+
33
+ ip = nil
34
+ lines.each { |line|
35
+
36
+ if line =~ /^#ip ([+-]?\d+)$/
37
+ ip = $1.to_i
38
+ end
39
+
40
+ if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
41
+ verb = $1
42
+ v1 = $2.to_i
43
+ v2 = $3.to_i
44
+ v3 = $4.to_i
45
+
46
+ commandQueue << [verb, v1, v2, v3]
47
+ end
48
+ }
49
+
50
+ if false
51
+ puts "Command queue:"
52
+ commandQueue.each { |x|
53
+ puts " " + x.inspect
54
+ }
55
+ end
56
+
57
+ ipp = 0
58
+ i = 0
59
+ reset = true
60
+
61
+ while ipp >= 0 && ipp < commandQueue.size
62
+
63
+ reg[ip] = ipp
64
+ command = commandQueue[ipp]
65
+
66
+ puts command.inspect + " " + reg.inspect if i % (256*1024) == 0
67
+ i += 1
68
+
69
+ case command[0]
70
+
71
+ when "addr"
72
+ # addr (add register) stores into register C the result of adding register A and register B.
73
+ reg[command[3]] = reg[command[1]] + reg[command[2]]
74
+
75
+ when "addi"
76
+ # addi (add immediate) stores into register C the result of adding register A and value B.
77
+ reg[command[3]] = reg[command[1]] + command[2]
78
+
79
+ when "mulr"
80
+ # mulr (multiply register) stores into register C the result of multiplying register A and register B.
81
+ reg[command[3]] = reg[command[1]] * reg[command[2]]
82
+
83
+ when "muli"
84
+ # muli (multiply immediate) stores into register C the result of multiplying register A and value B.
85
+ reg[command[3]] = reg[command[1]] * command[2]
86
+
87
+ when "banr"
88
+ # banr (bitwise AND register) stores into register C the result of the bitwise AND of register A and register B.
89
+ reg[command[3]] = reg[command[1]] & reg[command[2]]
90
+
91
+ when "bani"
92
+ # bani (bitwise AND immediate) stores into register C the result of the bitwise AND of register A and value B.
93
+ reg[command[3]] = reg[command[1]] & command[2]
94
+
95
+ when "borr"
96
+ # borr (bitwise OR register) stores into register C the result of the bitwise OR of register A and register B.
97
+ reg[command[3]] = reg[command[1]] | reg[command[2]]
98
+
99
+ when "bori"
100
+ # bori (bitwise OR immediate) stores into register C the result of the bitwise OR of register A and value B.
101
+ reg[command[3]] = reg[command[1]] | command[2]
102
+
103
+ when "setr"
104
+ # setr (set register) copies the contents of register A into register C. (Input B is ignored.)
105
+ reg[command[3]] = reg[command[1]]
106
+
107
+ when "seti"
108
+ # seti (set immediate) stores value A into register C. (Input B is ignored.)
109
+ reg[command[3]] = command[1]
110
+
111
+ when "gtir"
112
+ # 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.
113
+ reg[command[3]] = command[1] > reg[command[2]] ? 1 : 0
114
+
115
+ when "gtri"
116
+ # 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.
117
+ reg[command[3]] = reg[command[1]] > command[2] ? 1 : 0
118
+
119
+ when "gtrr"
120
+ # 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.
121
+ reg[command[3]] = reg[command[1]] > reg[command[2]] ? 1 : 0
122
+
123
+ when "eqir"
124
+ # eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
125
+ reg[command[3]] = command[1] == reg[command[2]] ? 1 : 0
126
+
127
+ when "eqri"
128
+ # eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
129
+ reg[command[3]] = reg[command[1]] == command[2] ? 1 : 0
130
+
131
+ when "eqrr"
132
+ # eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
133
+ reg[command[3]] = reg[command[1]] == reg[command[2]] ? 1 : 0
134
+
135
+ else
136
+ raise "Error"
137
+ end
138
+
139
+ ipp = reg[ip]
140
+ ipp += 1
141
+ end
142
+
143
+ puts reg.inspect
144
+ puts "Part#{part}: #{reg[0]}"
145
+ }
@@ -0,0 +1,103 @@
1
+ #
2
+ # https://adventofcode.com/2018/day/20 part 1 and 2
3
+ #
4
+ # Took 1:10 min for both parts (not bad!)
5
+ #
6
+ # Could have been faster, but ruzzles parts had to be created for this:
7
+ #
8
+ # - Grid.minmax
9
+ # - Point2D.from_s
10
+ # - Point2D.to_dir_bitmask / from_dir_bitmask
11
+ # - Dirs2D
12
+ #
13
+
14
+ require 'cem'
15
+
16
+ line = File.read("inputs/day20_input.txt")
17
+
18
+ stack = [[Point2D.new(500,500)]]
19
+
20
+ grid = Grid.new(1000, 1000, 0)
21
+
22
+ line.chars.each { |c|
23
+ case c
24
+
25
+ when '$'
26
+ # ignore
27
+ when '^'
28
+ # ignore
29
+ when "\n"
30
+ # ignore
31
+
32
+ when '('
33
+ newCurCursor = stack.last.map { |p| p.dup }
34
+ stack << [] # One below top() are all cursors we collected as part of this opening brace group
35
+ stack << newCurCursor # Stack.top() is all current cursor position we are tracking
36
+
37
+ when ')'
38
+ lastGroup = stack.pop
39
+ otherGroupsInBrace = stack.pop
40
+ replacedGroup = stack.pop
41
+ stack << (lastGroup + otherGroupsInBrace).uniq
42
+
43
+ when 'E', 'N', 'S', 'W'
44
+ dir = Point2D.from_s(c)
45
+
46
+ stack.last.map! { |p|
47
+ grid[p] |= dir.to_dir_bitmask
48
+ p += dir
49
+ grid[p] |= dir.flip.to_dir_bitmask
50
+ p
51
+ }
52
+ when '|'
53
+ lastGroup = stack.pop
54
+ stack.last.concat lastGroup
55
+ stack << stack[-2].map { |p| p.dup }
56
+
57
+ else
58
+ raise "Unknown char '#{c.inspect}'"
59
+ end
60
+ }
61
+
62
+ if false # Print Grid for debugging
63
+
64
+ min, max = grid.minmax(0)
65
+ count = 0
66
+
67
+ (min.y..max.y).each {|y|
68
+ a = ""
69
+ b = ""
70
+ (min.x..max.x).each { |x|
71
+ count += 1 if grid[y,x] > 0
72
+ a += "#" + (grid[y,x] & 1 == 1 ? "|" : "#")
73
+ b += (grid[y,x] & 8 == 8 ? "-" : "#") + (grid[y,x] > 0 ? "." : "#")
74
+ }
75
+ puts a + "#"
76
+ puts b + "#"
77
+ }
78
+
79
+ end
80
+
81
+ # Run BFS search
82
+ q = [[Point2D.new(500,500), 0]]
83
+
84
+ maxSteps = 0
85
+ rooms = 0
86
+ while q.size > 0
87
+ p, maxSteps = q.shift
88
+
89
+ if maxSteps >= 1000
90
+ rooms += 1
91
+ end
92
+
93
+ Point2D.from_dir_bitmask(grid[p]).each { |dir|
94
+ grid[p+dir] &= ~dir.flip.to_dir_bitmask # Close door we walked through. Due to BFS, we never have to get to it again
95
+
96
+ q << [p+dir, maxSteps+1]
97
+ }
98
+ grid[p] = 0
99
+
100
+ end
101
+
102
+ puts "Part 1: #{maxSteps}"
103
+ puts "Part 2: #{rooms}"