Files
adventofcode/2020/src/day25.rs

97 lines
2.1 KiB
Rust

use std::collections::HashMap;
use std::io::Read;
use crate::common::from_lines;
use crate::Solution;
const MOD_BASE: u32 = 20201227;
const SUBJECT_NUMBER: u32 = 7;
fn loop_count(public_key: u32) -> u64 {
discrete_log(SUBJECT_NUMBER, public_key, MOD_BASE).unwrap() as u64
}
// Implementation of the baby-step giant-step algorithm
//
// Based on:https://en.wikipedia.org/wiki/Baby-step_giant-step#C++_algorithm_(C++17)
fn discrete_log(g: u32, h: u32, mod_base: u32) -> Option<u32> {
let m = (mod_base as f64).sqrt().ceil() as u32;
let mut table = HashMap::with_capacity(m as usize);
let mut e: u32 = 1;
for i in 0..m {
table.insert(e, i);
e = ((e as u64 * g as u64) % mod_base as u64) as u32;
}
let factor = mod_exp(g as u64, (mod_base - m - 1) as u64, mod_base as u64);
e = h;
for i in 0..m {
if let Some(&val) = table.get(&e) {
return Some(i * m + val);
}
e = ((e as u64 * factor) % mod_base as u64) as u32;
}
None
}
#[inline]
fn mod_exp(base: u64, mut power: u64, mod_base: u64) -> u64 {
let mut result = 1;
let mut cur = base;
while power > 0 {
if power % 2 == 1 {
result *= cur;
result %= mod_base;
}
cur *= cur;
cur %= mod_base;
power /= 2;
}
result
}
#[derive(Default)]
pub struct Day25;
impl Solution for Day25 {
fn part1(&mut self, input: &mut dyn Read) -> String {
let nums: Vec<_> = from_lines(input);
let key_exponent = loop_count(nums[0]);
mod_exp(nums[1] as u64, key_exponent, MOD_BASE as u64).to_string()
}
fn part2(&mut self, _input: &mut dyn Read) -> String {
"Part 2 is free!".to_string()
}
}
#[cfg(test)]
mod tests {
use crate::test_implementation;
use super::*;
const SAMPLE: &[u8] = include_bytes!("../samples/25.txt");
#[test]
fn test_loop_count() {
assert_eq!(8, loop_count(5764801));
assert_eq!(11, loop_count(17807724));
}
#[test]
fn sample_part1() {
test_implementation(Day25, 1, SAMPLE, 14897079);
}
}