aboutsummaryrefslogtreecommitdiff
path: root/2022/17/b.rs
blob: 261dff46d6e89f2c572a85b73e02ae7110c37a6d (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
// Wow this is was terrible. Clearly you have to find out at which
// exact frequency the shape repeats, but I could not find a good
// way to estimate this apart from computing the first few (10^5)
// rows and then manually checking.

mod common;
use common::*;

fn line_to_u8(line: &[bool]) -> u8 {
    let mut r = 0;
    for i in 0..SCREEN_WIDTH {
        if line[i] { r |= 1 << i as u8; }
    }
    r
}

fn write_lines(screen: &Screen, v: &mut [u8]) {
    for i in 0..SCREEN_HEIGHT {
        v[i] = line_to_u8(&screen.cell[i]);
    }
}

fn isperiod(v: &[u8], l: usize) -> bool {
    const PERIOD_GUESS: usize = 10;
    const TIMES_MATCH: usize = 10;

    for i in 0..PERIOD_GUESS {
        for j in 1..TIMES_MATCH {
            if v[i] != v[i+j*l] { return false; }
        }
    }
    true
}

fn find_period(v: &[u8]) -> (usize, usize) {
    const PREP: usize = 1000;
    const PMAX: usize = 10000;

    for start in 0..PREP {
        for plen in 10..PMAX {
            if isperiod(&v[start..], plen) { return (start+1, plen); }
        }
    }
    panic!("No period of length < {} found with preperiod < {}",
        PMAX, PREP);
}

fn main() {
    const N: usize = 1000000000000;

    let mut screen = Screen::new();
    let rocks = get_rocks();
    let mut line = String::new();
    let _ = std::io::stdin().read_line(&mut line);
    let line = &line[0..line.len()-1]; // remove newline

    let mut i = 0;
    let mut t = 0;
    let mut vv = [0 as u8; SCREEN_HEIGHT];
    let mut ii = [0 as usize; SCREEN_HEIGHT];
    while screen.top < SCREEN_HEIGHT - 10 {
        screen.drop_rock(&rocks[i%5], &mut t, &line);
        ii[screen.top] = i;
        i += 1;
    }
    write_lines(&screen, &mut vv);
    let (prep, plen) = find_period(&vv);

    /* This part shows the period etc...
    println!("prep = {prep}, plen = {plen}");
    for j in 0..10 {
        for k in 0..4 {
            print!(" | t={:>4} i={:>4}", j+prep+k*plen, ii[j+prep+k*plen]);
        }
        println!();
    }
    */

    let i0 = ii[prep];
    let i1 = ii[prep+plen];

    let n = (N - i0) / (i1 - i0); // How many full repeats
    let t = n * plen + prep; // How tall is the thing after n full repeats
    // Remainder (unlike in the example case, it does not end with full repeat)
    let mut rem = 0;
    for j in 0..SCREEN_HEIGHT {
        if ii[j] >= i0 + (N - i0) % (i1 - i0) {
            rem = j-prep;
            break;
        }
    }
    println!("{}", t + rem - 1);
}

Generated with cgit - Back to sebastiano.tronto.net