aboutsummaryrefslogtreecommitdiff
path: root/aoc2017-gleam/src/aoc_2017/day_15.gleam
blob: e0557f56cef5bfba93ba46bff2317fa4e3226e16 (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
87
88
89
90
91
92
93
94
import gleam/int
import gleam/io
import gleam/string

const sixteen_bits = 0xFFFF

const generator_a = 16_807

const generator_b = 48_271

const divisor = 2_147_483_647

const max_reps_pt1 = 40_000_000

const max_reps_pt2 = 5_000_000

pub fn parse(input: String) {
  let assert Ok(#(a_str, b_str)) = string.split_once(input, ",")
  let assert Ok(a) = int.parse(a_str)
  let assert Ok(b) = int.parse(b_str)

  #(a, b)
}

pub fn pt_1(input: #(Int, Int)) {
  let #(a, b) = input

  next_comparison(
    a: a,
    b: b,
    selecting_a_using: next_value,
    selecting_b_using: next_value,
    initial_matches: 0,
    initial_cycle: 0,
    up_to: max_reps_pt1,
  )
}

pub fn pt_2(input: #(Int, Int)) {
  let #(a, b) = input

  next_comparison(
    a: a,
    b: b,
    selecting_a_using: next_but_divisible_by(4),
    selecting_b_using: next_but_divisible_by(8),
    initial_matches: 0,
    initial_cycle: 0,
    up_to: max_reps_pt2,
  )
}

fn next_value(current, generator) {
  { current * generator } % divisor
}

fn picky_generator(current, generator, divisible_by) {
  let trial = next_value(current, generator)
  case trial % divisible_by {
    0 -> trial
    _ -> picky_generator(trial, generator, divisible_by)
  }
}

fn next_but_divisible_by(divisible_by) {
  fn(c, g) { picky_generator(c, g, divisible_by) }
}

fn last_16_bits(n: Int) {
  int.bitwise_and(n, sixteen_bits)
}

fn next_comparison(
  a a: Int,
  b b: Int,
  selecting_a_using for_a: fn(Int, Int) -> Int,
  selecting_b_using for_b: fn(Int, Int) -> Int,
  initial_matches same: Int,
  initial_cycle count: Int,
  up_to max: Int,
) {
  case count == max {
    True -> same
    False -> {
      let next_a = for_a(a, generator_a)
      let next_b = for_b(b, generator_b)
      let maybe_same = case last_16_bits(next_a) == last_16_bits(next_b) {
        True -> same + 1
        False -> same
      }
      next_comparison(next_a, next_b, for_a, for_b, maybe_same, count + 1, max)
    }
  }
}