aboutsummaryrefslogtreecommitdiff
path: root/codingquest2024/src/day6/solution.gleam
blob: 8a0319cab4a9e56c27328e1a3d2f3ad7583af8be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import gleam/dict
import gleam/io
import gleam/list
import gleam/regex
import gleam/result
import gleam/string
import simplifile

pub opaque type Location {
  Location(row: Int, col: Int)
}

pub fn main() {
  let assert Ok(data) = simplifile.read(from: "./src/day6/data.txt")
  let assert ["Cipher key: " <> key, "Message: " <> raw_message] =
    string.split(data, "\n")

  let letter_to_location = make_cipher_grid(key)
  let location_to_letter =
    letter_to_location
    |> dict.fold(dict.new(), fn(acc, k, v) { dict.insert(acc, v, k) })

  raw_message
  |> string.split(" ")
  |> list.map(fn(s) {
    s
    |> string.to_graphemes
    |> list.sized_chunk(2)
  })
  |> list.map(fn(s) {
    s
    |> decode_word(letter_to_location, location_to_letter)
    |> string.concat()
  })
  |> string.join(" ")
  |> io.println()
}

fn make_cipher_grid(key) {
  let assert Ok(in_key) = regex.from_string("[" <> key <> "]")
  let grid =
    regex.split(in_key, "abcdefghiklmnopqrstuvwxyz")
    |> string.concat
    |> string.append(key, _)
    |> string.to_graphemes
    |> list.sized_chunk(5)

  list.index_map(grid, fn(row, r) {
    list.index_map(row, fn(cell, c) { #(cell, Location(r, c)) })
  })
  |> list.flatten
  |> dict.from_list
}

fn decode_word(word: List(List(String)), to_loc, to_letter) {
  case word {
    [] -> []
    [[a, b], ..rest] -> [
      transform_pair(a, b, to_loc, to_letter),
      ..decode_word(rest, to_loc, to_letter)
    ]
    _ -> panic as "bad playfair format"
  }
}

fn transform_pair(a, b, to_loc, to_letter) {
  let assert Ok(Location(r_a, c_a)) = dict.get(to_loc, a)
  let assert Ok(Location(r_b, c_b)) = dict.get(to_loc, b)

  case r_a == r_b, c_a == c_b {
    True, _ -> [
      dict.get(to_letter, Location(r_a, { c_a + 4 } % 5)),
      dict.get(to_letter, Location(r_b, { c_b + 4 } % 5)),
    ]
    _, True -> [
      dict.get(to_letter, Location({ r_a + 4 } % 5, c_a)),
      dict.get(to_letter, Location({ r_b + 4 } % 5, c_b)),
    ]
    _, _ -> [
      dict.get(to_letter, Location(r_a, c_b)),
      dict.get(to_letter, Location(r_b, c_a)),
    ]
  }
  |> result.values
  |> string.concat
}