diff --git a/2024/ruby/day_04.rb b/2024/ruby/day_04.rb
new file mode 100644
index 0000000..9f2add1
--- /dev/null
+++ b/2024/ruby/day_04.rb
@@ -0,0 +1,32 @@
+input = DATA.readlines(chomp: true)
+ .flat_map.with_index {|row, y|
+ row.chars.map.with_index {|chr, x|
+ [[y,x], chr]
+ }
+ }.to_h
+
+# part one
+dirs = (-1..1).flat_map {|dy| (-1..1).map {|dx| [dy,dx] }}
+dirs.delete([0,0])
+dirs = dirs.map {|dy, dx|
+ 4.times.map {|i| [dy*i, dx*i] }
+}
+
+pp input.keys.sum {|y, x|
+ dirs.count {|deltas|
+ deltas.map {|dy, dx| input[[y+dy, x+dx]] }.join == "XMAS"
+ }
+}
+
+# part two
+diagonals = [
+ [[-1, 1], [1, -1]],
+ [[-1, -1], [1, 1]],
+]
+pp input.keys.select {|y, x|
+ input[[y,x]] == ?A && diagonals.all? {|deltas|
+ deltas.map {|dy,dx| input[[y+dy, x+dx]] }.to_set == Set["M", "S"]
+ }
+}.size
+
+__END__