cem 0.1.4 → 0.1.5
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.
- checksums.yaml +4 -4
- data/examples/aoc2018/.gitignore +2 -0
- data/examples/aoc2018/day10.rb +61 -0
- data/examples/aoc2018/day11.rb +66 -0
- data/examples/aoc2018/day12.rb +61 -0
- data/examples/aoc2018/day13.rb +167 -0
- data/examples/aoc2018/day14.rb +31 -0
- data/examples/aoc2018/day14_2.rb +71 -0
- data/examples/aoc2018/day15.rb +271 -0
- data/examples/aoc2018/day16.rb +158 -0
- data/examples/aoc2018/day17.rb +203 -0
- data/examples/aoc2018/day18.rb +113 -0
- data/examples/aoc2018/day18_rspec.rb +131 -0
- data/examples/aoc2018/day19.rb +145 -0
- data/examples/aoc2018/day20.rb +103 -0
- data/examples/aoc2018/day21.rb +158 -0
- data/examples/aoc2018/day21_v2.rb +137 -0
- data/examples/aoc2018/day21_v3.rb +157 -0
- data/examples/aoc2018/day21_v4.rb +141 -0
- data/examples/aoc2018/day22.rb +212 -0
- data/examples/aoc2018/day23.rb +148 -0
- data/examples/aoc2018/day24.rb +156 -0
- data/examples/aoc2018/day25.rb +52 -0
- data/examples/aoc2018/day9.rb +51 -0
- data/examples/aoc2018/day9_circular.rb +125 -0
- data/examples/aoc2018/inputs/day10_input.txt +395 -0
- data/examples/aoc2018/inputs/day11_input.txt +1 -0
- data/examples/aoc2018/inputs/day12_input.txt +34 -0
- data/examples/aoc2018/inputs/day12_input2.txt +16 -0
- data/examples/aoc2018/inputs/day13_input.txt +150 -0
- data/examples/aoc2018/inputs/day13_test.txt +6 -0
- data/examples/aoc2018/inputs/day14_input.txt +1 -0
- data/examples/aoc2018/inputs/day15_input.txt +32 -0
- data/examples/aoc2018/inputs/day15_input10.txt +32 -0
- data/examples/aoc2018/inputs/day15_input11.txt +32 -0
- data/examples/aoc2018/inputs/day15_input12.txt +32 -0
- data/examples/aoc2018/inputs/day15_input13.txt +32 -0
- data/examples/aoc2018/inputs/day15_input14.txt +32 -0
- data/examples/aoc2018/inputs/day15_input2.txt +7 -0
- data/examples/aoc2018/inputs/day15_input3.txt +9 -0
- data/examples/aoc2018/inputs/day15_input4.txt +7 -0
- data/examples/aoc2018/inputs/day15_input5.txt +7 -0
- data/examples/aoc2018/inputs/day15_input6.txt +7 -0
- data/examples/aoc2018/inputs/day15_input7.txt +7 -0
- data/examples/aoc2018/inputs/day15_input8.txt +5 -0
- data/examples/aoc2018/inputs/day15_input9.txt +7 -0
- data/examples/aoc2018/inputs/day15_test.txt +9 -0
- data/examples/aoc2018/inputs/day16_input.txt +3865 -0
- data/examples/aoc2018/inputs/day17_input.txt +2229 -0
- data/examples/aoc2018/inputs/day17_input_test.txt +8 -0
- data/examples/aoc2018/inputs/day18_input.txt +50 -0
- data/examples/aoc2018/inputs/day18_test.txt +10 -0
- data/examples/aoc2018/inputs/day19_input.txt +48 -0
- data/examples/aoc2018/inputs/day20_input.txt +1 -0
- data/examples/aoc2018/inputs/day21_input.txt +32 -0
- data/examples/aoc2018/inputs/day22_input.txt +2 -0
- data/examples/aoc2018/inputs/day23_input.txt +1000 -0
- data/examples/aoc2018/inputs/day23_input2.txt +9 -0
- data/examples/aoc2018/inputs/day24_input.txt +24 -0
- data/examples/aoc2018/inputs/day25_input.txt +1483 -0
- data/examples/aoc2018/inputs/day9_input.txt +1 -0
- data/lib/cem.rb +0 -6
- data/lib/cem/ccommon.rb +45 -0
- data/lib/cem/cruzzles.rb +93 -38
- data/lib/cem/version.rb +1 -1
- metadata +62 -2
@@ -0,0 +1 @@
|
|
1
|
+
428 players; last marble is worth 70825 points
|
data/lib/cem.rb
CHANGED
data/lib/cem/ccommon.rb
CHANGED
@@ -11,6 +11,28 @@ rescue LoadError
|
|
11
11
|
require requireName
|
12
12
|
end
|
13
13
|
|
14
|
+
#
|
15
|
+
# Puts+eql? == peql
|
16
|
+
# Performs a equal comparison and outputs the result to console in the form
|
17
|
+
#
|
18
|
+
# "#{msg}: Expected #{expected}, but got #{actual}"
|
19
|
+
#
|
20
|
+
# expected may be kept empty, in which case the msg is adjusted
|
21
|
+
#
|
22
|
+
def peql(actual, expected=:unknown_peql_token, msg=nil)
|
23
|
+
|
24
|
+
if expected == :unknown_peql_token
|
25
|
+
puts "#{msg}: Didn't know what to expect and got '#{actual}'"
|
26
|
+
else
|
27
|
+
if actual == expected
|
28
|
+
puts "#{msg}: Expected '#{expected}' and got it!"
|
29
|
+
else
|
30
|
+
puts "#{msg}: Expected '#{expected}', but got '#{actual}!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
14
36
|
class File
|
15
37
|
|
16
38
|
# Returns the first match of the given files
|
@@ -24,6 +46,29 @@ class File
|
|
24
46
|
end
|
25
47
|
end
|
26
48
|
|
49
|
+
class Module
|
50
|
+
|
51
|
+
# Append only the given methods from the given mod(ule)
|
52
|
+
# Adapted from: https://www.ruby-forum.com/t/partial-append-features/66728/12
|
53
|
+
# Why? Enumerable has too many methods to include at once.
|
54
|
+
def append_from( module_to_append_from, *methods_to_keep )
|
55
|
+
methods_to_keep.map! { |m| m.to_sym }
|
56
|
+
|
57
|
+
methods_to_remove = module_to_append_from.instance_methods(false) - methods_to_keep
|
58
|
+
|
59
|
+
new_mod = Module.new
|
60
|
+
new_mod.module_eval do
|
61
|
+
include module_to_append_from
|
62
|
+
methods_to_remove.each { |meth| undef_method meth }
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sanity check:
|
66
|
+
check = methods_to_keep - new_mod.instance_methods(true)
|
67
|
+
raise "The following methods are not in the given module: #{check.inspect}" if !check.empty?
|
68
|
+
|
69
|
+
include new_mod
|
70
|
+
end
|
71
|
+
end
|
27
72
|
|
28
73
|
|
29
74
|
class Array
|
data/lib/cem/cruzzles.rb
CHANGED
@@ -128,29 +128,57 @@ Point2D = Struct.new("Point2D", :x, :y) {
|
|
128
128
|
[array.reduce { |min, o| min.min(o) }, array.reduce { |max, o| max.max(o) } ]
|
129
129
|
end
|
130
130
|
|
131
|
+
def add!(other)
|
132
|
+
self.x += other.x
|
133
|
+
self.y += other.y
|
134
|
+
return self
|
135
|
+
end
|
136
|
+
|
131
137
|
def left
|
132
|
-
|
138
|
+
self + Dir2D::LEFT
|
133
139
|
end
|
134
140
|
|
135
141
|
def left!
|
136
|
-
|
137
|
-
y += Dir2D.LEFT.y
|
138
|
-
return self
|
142
|
+
add!(Dir2D::LEFT)
|
139
143
|
end
|
140
144
|
|
145
|
+
def right
|
146
|
+
self + Dir2D::RIGHT
|
147
|
+
end
|
148
|
+
|
149
|
+
def right!
|
150
|
+
add!(Dir2D::RIGHT)
|
151
|
+
end
|
152
|
+
|
153
|
+
def up
|
154
|
+
self + Dir2D::UP
|
155
|
+
end
|
156
|
+
|
157
|
+
def up!
|
158
|
+
add!(Dir2D::UP)
|
159
|
+
end
|
160
|
+
|
161
|
+
def down
|
162
|
+
self + Dir2D::DOWN
|
163
|
+
end
|
141
164
|
|
165
|
+
def down!
|
166
|
+
add!(Dir2D::DOWN)
|
167
|
+
end
|
168
|
+
|
142
169
|
def to_dir_bitmask
|
143
170
|
|
144
|
-
|
171
|
+
case self
|
172
|
+
when Dir2D::N
|
145
173
|
return 1
|
146
|
-
|
174
|
+
when Dir2D::E
|
147
175
|
return 2
|
148
|
-
|
176
|
+
when Dir2D::S
|
149
177
|
return 4
|
150
|
-
|
178
|
+
when Dir2D::W
|
151
179
|
return 8
|
152
180
|
else
|
153
|
-
raise self.
|
181
|
+
raise "Only Dir2Ds can be converted to direction bitmask: #{self.inspect}"
|
154
182
|
end
|
155
183
|
end
|
156
184
|
|
@@ -158,16 +186,16 @@ Point2D = Struct.new("Point2D", :x, :y) {
|
|
158
186
|
|
159
187
|
result = []
|
160
188
|
if v & 1 > 0
|
161
|
-
result <<
|
189
|
+
result << Dir2D::N
|
162
190
|
end
|
163
191
|
if v & 2 > 0
|
164
|
-
result <<
|
192
|
+
result << Dir2D::E
|
165
193
|
end
|
166
194
|
if v & 4 > 0
|
167
|
-
result <<
|
195
|
+
result << Dir2D::S
|
168
196
|
end
|
169
197
|
if v & 8 > 0
|
170
|
-
result <<
|
198
|
+
result << Dir2D::W
|
171
199
|
end
|
172
200
|
return result
|
173
201
|
end
|
@@ -205,14 +233,14 @@ Seg2D = Struct.new("Seg2D", :p1, :p2) {
|
|
205
233
|
|
206
234
|
}
|
207
235
|
|
208
|
-
Dirs2D = [Point2D.new(0, -1), Point2D.new(1, 0), Point2D.new(0, 1), Point2D.new(-1, 0)]
|
209
|
-
|
210
236
|
class Dir2D < Point2D
|
211
237
|
|
212
|
-
N = UP = Dir2D.new( 0, -1)
|
213
|
-
E = RIGHT = Dir2D.new( 1, 0)
|
214
|
-
S = DOWN = Dir2D.new( 0, 1)
|
215
|
-
W = LEFT = Dir2D.new(-1, 0)
|
238
|
+
N = UP = Dir2D.new( 0, -1).freeze
|
239
|
+
E = RIGHT = Dir2D.new( 1, 0).freeze
|
240
|
+
S = DOWN = Dir2D.new( 0, 1).freeze
|
241
|
+
W = LEFT = Dir2D.new(-1, 0).freeze
|
242
|
+
|
243
|
+
All = [N, E, S, W]
|
216
244
|
|
217
245
|
#
|
218
246
|
# Dir2D * Range = array of Dir2D
|
@@ -237,13 +265,13 @@ class Dir2D < Point2D
|
|
237
265
|
def self.x(length=1)
|
238
266
|
return vert(length) + hori(length)
|
239
267
|
end
|
240
|
-
|
241
268
|
end
|
242
|
-
|
269
|
+
|
270
|
+
Dirs2D = Dir2D::All
|
243
271
|
|
244
272
|
class Grid
|
245
273
|
|
246
|
-
|
274
|
+
attr_accessor :data
|
247
275
|
|
248
276
|
def initialize(x, y, default=0, &block)
|
249
277
|
|
@@ -323,6 +351,12 @@ class Grid
|
|
323
351
|
return result
|
324
352
|
end
|
325
353
|
|
354
|
+
# Mixin all methods which make sense:
|
355
|
+
# - Searching if all/any/none/one value matches something
|
356
|
+
append_from(Enumerable, :any?, :all?, :include?, :member?, :none?, :one?, :tally, :count)
|
357
|
+
|
358
|
+
|
359
|
+
# Finds the top-left (min), bottom-right (max) coordinates of this Grid using the given value 'null' as an indicator for an empty field.
|
326
360
|
def minmax(null=nil)
|
327
361
|
min = nil
|
328
362
|
max = nil
|
@@ -374,10 +408,11 @@ class Grid
|
|
374
408
|
return @data[y][x] = assign
|
375
409
|
end
|
376
410
|
|
377
|
-
|
411
|
+
# Returns the underlying 2D array as a flattened array
|
412
|
+
def flatten
|
378
413
|
return @data.flatten
|
379
|
-
end
|
380
|
-
|
414
|
+
end
|
415
|
+
|
381
416
|
#
|
382
417
|
# Returns the Point2Ds in the directions NSEW as an array (no diagonals, see adja_index for this)
|
383
418
|
#
|
@@ -437,7 +472,7 @@ class Grid
|
|
437
472
|
result << Point2D.new(x-1,y-1)
|
438
473
|
end
|
439
474
|
result << Point2D.new(x-1,y)
|
440
|
-
if y + 1 < @data.size
|
475
|
+
if y + 1 < @data.size
|
441
476
|
result << Point2D.new(x-1, y+1)
|
442
477
|
end
|
443
478
|
end
|
@@ -447,15 +482,15 @@ class Grid
|
|
447
482
|
|
448
483
|
# result << Point2D.new(x,y)
|
449
484
|
|
450
|
-
if y + 1 < @data.size
|
485
|
+
if y + 1 < @data.size
|
451
486
|
result << Point2D.new(x, y+1)
|
452
487
|
end
|
453
|
-
if x + 1 < @data[0].size
|
488
|
+
if x + 1 < @data[0].size
|
454
489
|
if y > 0
|
455
490
|
result << Point2D.new(x+1,y-1)
|
456
491
|
end
|
457
492
|
result << Point2D.new(x+1,y)
|
458
|
-
if y + 1 < @data.size
|
493
|
+
if y + 1 < @data.size
|
459
494
|
result << Point2D.new(x+1, y+1)
|
460
495
|
end
|
461
496
|
end
|
@@ -466,13 +501,13 @@ class Grid
|
|
466
501
|
printBoard()
|
467
502
|
end
|
468
503
|
|
469
|
-
#
|
470
504
|
# returns a copy of the underlying 2D array, with linking to the content (rather than dup the content also)
|
471
|
-
#
|
472
505
|
def to_a
|
473
506
|
@data.map { |row| row.dup }
|
474
507
|
end
|
475
508
|
|
509
|
+
# Returns access to the underlying 2D array.
|
510
|
+
# Caution: This is not a duplicate. Use to_a for this.
|
476
511
|
def data
|
477
512
|
@data
|
478
513
|
end
|
@@ -482,24 +517,30 @@ class Grid
|
|
482
517
|
#
|
483
518
|
# If block has...
|
484
519
|
# - one parameter, passes the cell value
|
485
|
-
# - two parameters, passes
|
520
|
+
# - two parameters, passes the coordinates as a Point2D and the cell value
|
486
521
|
# - three parameteres, passes y, x and the cell value
|
487
522
|
#
|
523
|
+
# If the block returns nil, the original value is kept.
|
524
|
+
#
|
488
525
|
def map_a(&block)
|
489
526
|
|
490
527
|
case block.arity
|
491
528
|
when 1
|
492
|
-
@data.map { |row| row.map { |value| block.call(value) } }
|
529
|
+
@data.map { |row| row.map { |value| block.call(value) || value } }
|
493
530
|
when 2
|
494
|
-
@data.each_with_index.map { |row, y| row.
|
531
|
+
@data.each_with_index.map { |row, y| row.each_with_index.map { |value, x| block.call(Point2D.new(x, y), value) || value } }
|
495
532
|
when 3
|
496
|
-
@data.each_with_index.map { |row, y| row.each_with_index.map { |
|
533
|
+
@data.each_with_index.map { |row, y| row.each_with_index.map { |value, x| block.call(y, x, value) || value} }
|
497
534
|
else
|
498
535
|
raise
|
499
536
|
end
|
500
537
|
|
501
538
|
end
|
502
539
|
|
540
|
+
def map_a!(&block)
|
541
|
+
@data = map_a(&block)
|
542
|
+
end
|
543
|
+
|
503
544
|
def each(&block)
|
504
545
|
@data.each { |row|
|
505
546
|
row.each { |cell|
|
@@ -603,7 +644,21 @@ Point3D = Struct.new("Point3D", :x, :y, :z) {
|
|
603
644
|
end
|
604
645
|
end
|
605
646
|
}
|
606
|
-
|
607
|
-
|
608
647
|
|
609
|
-
|
648
|
+
Point4D = Struct.new("Point4D", :x, :y, :z, :w) {
|
649
|
+
|
650
|
+
def manhattan(other=nil)
|
651
|
+
if other != nil
|
652
|
+
return (self - other).manhattan
|
653
|
+
end
|
654
|
+
return x.abs + y.abs + z.abs + w.abs
|
655
|
+
end
|
656
|
+
|
657
|
+
def -(other)
|
658
|
+
Point4D.new(x - other.x, y - other.y, z - other.z, w - other.w)
|
659
|
+
end
|
660
|
+
|
661
|
+
def to_s
|
662
|
+
"#{x}, #{y}, #{z}, #{w}"
|
663
|
+
end
|
664
|
+
}
|
data/lib/cem/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Özbek
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -83,9 +83,31 @@ files:
|
|
83
83
|
- bin/console
|
84
84
|
- bin/setup
|
85
85
|
- cem.gemspec
|
86
|
+
- examples/aoc2018/.gitignore
|
86
87
|
- examples/aoc2018/day1.rb
|
88
|
+
- examples/aoc2018/day10.rb
|
89
|
+
- examples/aoc2018/day11.rb
|
90
|
+
- examples/aoc2018/day12.rb
|
91
|
+
- examples/aoc2018/day13.rb
|
92
|
+
- examples/aoc2018/day14.rb
|
93
|
+
- examples/aoc2018/day14_2.rb
|
94
|
+
- examples/aoc2018/day15.rb
|
95
|
+
- examples/aoc2018/day16.rb
|
96
|
+
- examples/aoc2018/day17.rb
|
97
|
+
- examples/aoc2018/day18.rb
|
98
|
+
- examples/aoc2018/day18_rspec.rb
|
99
|
+
- examples/aoc2018/day19.rb
|
87
100
|
- examples/aoc2018/day1_part2.rb
|
88
101
|
- examples/aoc2018/day2.rb
|
102
|
+
- examples/aoc2018/day20.rb
|
103
|
+
- examples/aoc2018/day21.rb
|
104
|
+
- examples/aoc2018/day21_v2.rb
|
105
|
+
- examples/aoc2018/day21_v3.rb
|
106
|
+
- examples/aoc2018/day21_v4.rb
|
107
|
+
- examples/aoc2018/day22.rb
|
108
|
+
- examples/aoc2018/day23.rb
|
109
|
+
- examples/aoc2018/day24.rb
|
110
|
+
- examples/aoc2018/day25.rb
|
89
111
|
- examples/aoc2018/day2_2.rb
|
90
112
|
- examples/aoc2018/day3.rb
|
91
113
|
- examples/aoc2018/day4.rb
|
@@ -95,7 +117,44 @@ files:
|
|
95
117
|
- examples/aoc2018/day7.rb
|
96
118
|
- examples/aoc2018/day8.rb
|
97
119
|
- examples/aoc2018/day8_part2.rb
|
120
|
+
- examples/aoc2018/day9.rb
|
121
|
+
- examples/aoc2018/day9_circular.rb
|
122
|
+
- examples/aoc2018/inputs/day10_input.txt
|
123
|
+
- examples/aoc2018/inputs/day11_input.txt
|
124
|
+
- examples/aoc2018/inputs/day12_input.txt
|
125
|
+
- examples/aoc2018/inputs/day12_input2.txt
|
126
|
+
- examples/aoc2018/inputs/day13_input.txt
|
127
|
+
- examples/aoc2018/inputs/day13_test.txt
|
128
|
+
- examples/aoc2018/inputs/day14_input.txt
|
129
|
+
- examples/aoc2018/inputs/day15_input.txt
|
130
|
+
- examples/aoc2018/inputs/day15_input10.txt
|
131
|
+
- examples/aoc2018/inputs/day15_input11.txt
|
132
|
+
- examples/aoc2018/inputs/day15_input12.txt
|
133
|
+
- examples/aoc2018/inputs/day15_input13.txt
|
134
|
+
- examples/aoc2018/inputs/day15_input14.txt
|
135
|
+
- examples/aoc2018/inputs/day15_input2.txt
|
136
|
+
- examples/aoc2018/inputs/day15_input3.txt
|
137
|
+
- examples/aoc2018/inputs/day15_input4.txt
|
138
|
+
- examples/aoc2018/inputs/day15_input5.txt
|
139
|
+
- examples/aoc2018/inputs/day15_input6.txt
|
140
|
+
- examples/aoc2018/inputs/day15_input7.txt
|
141
|
+
- examples/aoc2018/inputs/day15_input8.txt
|
142
|
+
- examples/aoc2018/inputs/day15_input9.txt
|
143
|
+
- examples/aoc2018/inputs/day15_test.txt
|
144
|
+
- examples/aoc2018/inputs/day16_input.txt
|
145
|
+
- examples/aoc2018/inputs/day17_input.txt
|
146
|
+
- examples/aoc2018/inputs/day17_input_test.txt
|
147
|
+
- examples/aoc2018/inputs/day18_input.txt
|
148
|
+
- examples/aoc2018/inputs/day18_test.txt
|
149
|
+
- examples/aoc2018/inputs/day19_input.txt
|
98
150
|
- examples/aoc2018/inputs/day1_input.txt
|
151
|
+
- examples/aoc2018/inputs/day20_input.txt
|
152
|
+
- examples/aoc2018/inputs/day21_input.txt
|
153
|
+
- examples/aoc2018/inputs/day22_input.txt
|
154
|
+
- examples/aoc2018/inputs/day23_input.txt
|
155
|
+
- examples/aoc2018/inputs/day23_input2.txt
|
156
|
+
- examples/aoc2018/inputs/day24_input.txt
|
157
|
+
- examples/aoc2018/inputs/day25_input.txt
|
99
158
|
- examples/aoc2018/inputs/day2_input.txt
|
100
159
|
- examples/aoc2018/inputs/day3_input.txt
|
101
160
|
- examples/aoc2018/inputs/day4_input.txt
|
@@ -103,6 +162,7 @@ files:
|
|
103
162
|
- examples/aoc2018/inputs/day6_input.txt
|
104
163
|
- examples/aoc2018/inputs/day7_input.txt
|
105
164
|
- examples/aoc2018/inputs/day8_input.txt
|
165
|
+
- examples/aoc2018/inputs/day9_input.txt
|
106
166
|
- lib/cem.rb
|
107
167
|
- lib/cem/ccommon.rb
|
108
168
|
- lib/cem/cflame.rb
|