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
}
|