Apparently a bug in PE 089 but can't for the life of me figure out what goes wrong
This commit is contained in:
273
projecteuler/089/src/main.rs
Normal file
273
projecteuler/089/src/main.rs
Normal file
@@ -0,0 +1,273 @@
|
||||
use nom::{
|
||||
branch::alt,
|
||||
character::complete::{char, multispace1},
|
||||
multi::{many1, separated_list1},
|
||||
IResult, Parser,
|
||||
};
|
||||
use std::{time::Instant, vec};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
enum RomanNum {
|
||||
I,
|
||||
V,
|
||||
X,
|
||||
L,
|
||||
C,
|
||||
D,
|
||||
M,
|
||||
Empty,
|
||||
}
|
||||
use RomanNum::*;
|
||||
type RomanNumeral = Vec<RomanNum>;
|
||||
|
||||
// This function is not correct at all but I'm not gonna bother fixing it
|
||||
fn _is_minimal(number: &RomanNumeral) -> bool {
|
||||
let mut last_num = Empty;
|
||||
let mut occ = 0;
|
||||
|
||||
for num in number.iter() {
|
||||
if *num == last_num {
|
||||
occ += 1;
|
||||
} else {
|
||||
last_num = *num;
|
||||
occ = 1;
|
||||
}
|
||||
|
||||
if occ > 3 && (last_num == I || last_num == X || last_num == C) {
|
||||
return false;
|
||||
// } else if occ > 1 && (last_num == V || last_num == L || last_num == D) {
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn reduce(original: &RomanNumeral) -> RomanNumeral {
|
||||
let mut last_num = Empty;
|
||||
let mut occ = 0;
|
||||
let mut result = vec![];
|
||||
|
||||
let mut number = original.clone();
|
||||
number.push(Empty);
|
||||
|
||||
for num in number.iter() {
|
||||
if *num == last_num {
|
||||
occ += 1;
|
||||
|
||||
if occ == 10 {
|
||||
match last_num {
|
||||
I => result.push(X),
|
||||
X => result.push(C),
|
||||
C => result.push(M),
|
||||
M => {
|
||||
for _ in 0..occ {
|
||||
result.push(M);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
occ -= 10;
|
||||
}
|
||||
} else {
|
||||
if occ < 4 {
|
||||
for _ in 0..occ {
|
||||
result.push(last_num);
|
||||
}
|
||||
} else if occ == 4 {
|
||||
match last_num {
|
||||
I => {
|
||||
result.push(I);
|
||||
result.push(V);
|
||||
}
|
||||
X => {
|
||||
result.push(X);
|
||||
result.push(L);
|
||||
}
|
||||
C => {
|
||||
result.push(C);
|
||||
result.push(D);
|
||||
}
|
||||
M => {
|
||||
for _ in 0..occ {
|
||||
result.push(M);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if occ == 5 {
|
||||
match last_num {
|
||||
I => result.push(V),
|
||||
X => result.push(L),
|
||||
C => result.push(D),
|
||||
M => {
|
||||
for _ in 0..occ {
|
||||
result.push(M);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if occ >= 6 && occ <= 8 {
|
||||
match last_num {
|
||||
I => {
|
||||
result.push(V);
|
||||
for _ in 0..occ - 5 {
|
||||
result.push(I);
|
||||
}
|
||||
}
|
||||
X => {
|
||||
result.push(L);
|
||||
for _ in 0..occ - 5 {
|
||||
result.push(X);
|
||||
}
|
||||
}
|
||||
C => {
|
||||
result.push(D);
|
||||
for _ in 0..occ - 5 {
|
||||
result.push(C);
|
||||
}
|
||||
}
|
||||
M => {
|
||||
for _ in 0..occ {
|
||||
result.push(M);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if occ == 9 {
|
||||
match last_num {
|
||||
I => {
|
||||
result.push(I);
|
||||
result.push(X);
|
||||
}
|
||||
X => {
|
||||
result.push(X);
|
||||
result.push(C);
|
||||
}
|
||||
C => {
|
||||
result.push(C);
|
||||
result.push(M);
|
||||
}
|
||||
M => {
|
||||
for _ in 0..occ {
|
||||
result.push(M);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
last_num = *num;
|
||||
occ = 1;
|
||||
}
|
||||
// println!("{:?}", result);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn reduce_extra(numeral: &RomanNumeral) -> RomanNumeral {
|
||||
if numeral.len() <= 3 {
|
||||
return numeral.clone();
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
let mut window = vec![Empty, numeral[0], numeral[1]];
|
||||
let mut i = 2;
|
||||
|
||||
while i < numeral.len() {
|
||||
result.push(window[0]);
|
||||
window[0] = window[1];
|
||||
window[1] = window[2];
|
||||
window[2] = numeral[i];
|
||||
|
||||
if window[0] == V && window[1] == I && window[2] == V {
|
||||
result.push(I);
|
||||
result.push(X);
|
||||
|
||||
window[1] = Empty;
|
||||
window[2] = Empty;
|
||||
} else if window[0] == L && window[1] == X && window[2] == L {
|
||||
result.push(X);
|
||||
result.push(C);
|
||||
|
||||
window[1] = Empty;
|
||||
window[2] = Empty;
|
||||
} else if window[0] == D && window[1] == C && window[2] == D {
|
||||
result.push(C);
|
||||
result.push(M);
|
||||
|
||||
window[1] = Empty;
|
||||
window[2] = Empty;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
result.push(window[0]);
|
||||
result.push(window[1]);
|
||||
result.push(window[2]);
|
||||
|
||||
result.into_iter().filter(|&n| n != Empty).collect()
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> IResult<&str, Vec<RomanNumeral>> {
|
||||
let (input, result) = separated_list1(
|
||||
multispace1,
|
||||
many1(
|
||||
alt((
|
||||
char('I'),
|
||||
char('V'),
|
||||
char('X'),
|
||||
char('L'),
|
||||
char('C'),
|
||||
char('D'),
|
||||
char('M'),
|
||||
))
|
||||
.map(|c| match c {
|
||||
'I' => I,
|
||||
'V' => V,
|
||||
'X' => X,
|
||||
'L' => L,
|
||||
'C' => C,
|
||||
'D' => D,
|
||||
'M' => M,
|
||||
_ => Empty,
|
||||
}),
|
||||
),
|
||||
)(input)?;
|
||||
|
||||
Ok((input, result))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, this is Patrick!");
|
||||
let now = Instant::now();
|
||||
|
||||
let input_text = include_str!("../roman.txt");
|
||||
|
||||
// let res = parse_input(input_text);
|
||||
// println!("{:?}", res);
|
||||
|
||||
let (_, numerals) = parse_input(input_text).unwrap();
|
||||
|
||||
let mut result = 0;
|
||||
for mut numeral in numerals {
|
||||
let start = numeral.len();
|
||||
let mut s = start;
|
||||
loop {
|
||||
numeral = reduce(&numeral);
|
||||
numeral = reduce_extra(&numeral);
|
||||
if s == numeral.len() {
|
||||
break;
|
||||
}
|
||||
s = numeral.len();
|
||||
}
|
||||
result += start - numeral.len();
|
||||
println!("{:?} , {}", numeral, start - numeral.len());
|
||||
}
|
||||
|
||||
println!("The number of characters that can be saved is: {}", result);
|
||||
|
||||
println!("Time passed: {:?}", Instant::now() - now);
|
||||
}
|
||||
Reference in New Issue
Block a user