Skip to content

Commit 10b8fb4

Browse files
2024 day 4
1 parent 3e8965b commit 10b8fb4

File tree

5 files changed

+586
-0
lines changed

5 files changed

+586
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
class WordSearch
2+
attr_reader :data, :word
3+
4+
def initialize(data, word = "XMAS")
5+
@data = data
6+
@word = word
7+
end
8+
9+
def in_bounds?(row, col)
10+
row.between?(0, data.length - 1) && col.between?(0, data[row].length - 1)
11+
end
12+
13+
def count_at(row, col)
14+
count = 0
15+
count += 1 if horizontal?(row, col)
16+
count += 1 if vertical?(row, col)
17+
count += diagonal_count_at(row, col)
18+
count
19+
end
20+
21+
def horizontal_word(row, col)
22+
first = col
23+
last = col + word.length - 1
24+
25+
return "" unless in_bounds?(first, last)
26+
27+
data[row][first..last] * ''
28+
end
29+
30+
def horizontal?(row, col)
31+
match?(horizontal_word(row, col))
32+
end
33+
34+
def vertical_word(row, col)
35+
first = row
36+
last = row + word.length - 1
37+
38+
return "" unless in_bounds?(first, last)
39+
40+
str = ""
41+
42+
data.each_index do |r|
43+
data[r].each_index do |c|
44+
str << data[r][c] if col == c && r.between?(first, last)
45+
end
46+
end
47+
48+
str
49+
end
50+
51+
def vertical?(row, col)
52+
match?(vertical_word(row, col))
53+
end
54+
55+
def diagonal_top_left_word(row, col)
56+
str = ""
57+
58+
(0..word.length - 1).each do |pos|
59+
new_row = row - pos
60+
new_col = col - pos
61+
62+
return str unless in_bounds?(new_row, new_col)
63+
64+
str += data[new_row][new_col]
65+
end
66+
67+
str
68+
end
69+
70+
def diagonal_top_right_word(row, col)
71+
str = ""
72+
73+
(0..word.length - 1).each do |pos|
74+
new_row = row - pos
75+
new_col = col + pos
76+
77+
return str unless in_bounds?(new_row, new_col)
78+
79+
str += data[new_row][new_col]
80+
end
81+
82+
str
83+
end
84+
85+
def letter_at(row, col)
86+
in_bounds?(row, col) ? data[row][col] : ""
87+
end
88+
89+
def diagonal_bottom_right_word(row, col)
90+
str = ""
91+
92+
(0..word.length - 1).each do |pos|
93+
new_row = row + pos
94+
new_col = col + pos
95+
96+
return str unless in_bounds?(new_row, new_col)
97+
98+
str += data[new_row][new_col]
99+
end
100+
101+
str
102+
end
103+
104+
def diagonal_bottom_left_word(row, col)
105+
str = ""
106+
107+
(0..word.length - 1).each do |pos|
108+
new_row = row + pos
109+
new_col = col - pos
110+
111+
return str unless in_bounds?(new_row, new_col)
112+
113+
str += data[new_row][new_col]
114+
end
115+
116+
str
117+
end
118+
119+
def match?(str)
120+
[str, str.reverse].any? { |w| w == word }
121+
end
122+
123+
def cross_word_at?(row, col)
124+
cross_word = "MAS"
125+
126+
diag_1 = letter_at(row-1, col-1) + letter_at(row, col) + letter_at(row+1, col+1)
127+
diag_2 = letter_at(row+1, col-1) + letter_at(row, col) + letter_at(row-1, col+1)
128+
129+
diag_1_match = [cross_word, cross_word.reverse].any? { |str| str == diag_1 }
130+
diag_2_match = [cross_word, cross_word.reverse].any? { |str| str == diag_2 }
131+
132+
diag_1_match && diag_2_match
133+
end
134+
135+
def cross_word_count
136+
count = 0
137+
138+
data.each_index do |x|
139+
data[x].each_index do |y|
140+
count += 1 if cross_word_at?(x, y)
141+
end
142+
end
143+
144+
count
145+
end
146+
147+
def word_count
148+
count = 0
149+
150+
data.each_index do |x|
151+
data[x].each_index do |y|
152+
count += count_at(x, y)
153+
end
154+
end
155+
156+
count
157+
end
158+
159+
def vertical_count
160+
count = 0
161+
data.each_index do |x|
162+
data[x].each_index do |y|
163+
count += 1 if vertical?(x, y)
164+
end
165+
end
166+
167+
count
168+
end
169+
170+
def horizonal_count
171+
count = 0
172+
data.each_index do |x|
173+
data[x].each_index do |y|
174+
count += 1 if horizontal?(x, y)
175+
end
176+
end
177+
178+
count
179+
end
180+
181+
def diagonal_count_at(row, col)
182+
count = 0
183+
count += 1 if diagonal_top_right_word(row, col) == word
184+
count += 1 if diagonal_top_left_word(row, col) == word
185+
count += 1 if diagonal_bottom_right_word(row, col) == word
186+
count += 1 if diagonal_bottom_left_word(row, col) == word
187+
count
188+
end
189+
190+
def diagonal_count
191+
count = 0
192+
193+
data.each_index do |x|
194+
data[x].each_index do |y|
195+
count += diagonal_count_at(x, y)
196+
end
197+
end
198+
199+
count
200+
end
201+
202+
def log_match(prefix, row, col, check)
203+
puts "[#{prefix} MATCH] #{row}, #{col}: #{data[row][col]} [#{check}]"
204+
end
205+
206+
def render
207+
data.each_index do |x|
208+
data[x].each_index do |y|
209+
print " #{data[x][y]} "
210+
end
211+
puts
212+
end
213+
end
214+
end

0 commit comments

Comments
 (0)