day7: optimized

This commit is contained in:
Ishan Jain 2023-12-07 13:54:17 +05:30
parent fc31940164
commit 73f0b5dc61
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27
2 changed files with 218 additions and 160 deletions

View File

@ -1,15 +1,19 @@
#![feature(byte_slice_trim_ascii)]
#![feature(test)] #![feature(test)]
use std::cmp::Ordering; use std::cmp::Ordering;
extern crate test; extern crate test;
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")]; const INPUTS: [&[u8]; 2] = [
include_bytes!("./sample.txt"),
include_bytes!("./input.txt"),
];
#[derive(Debug)] #[derive(Debug)]
struct Card { struct Card<'a> {
val: String, val: &'a [u8],
ttype: SetType, set_type: SetType,
} }
#[derive(Debug, Eq, PartialEq, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Clone, Copy)]
@ -23,59 +27,66 @@ enum SetType {
High = 1, High = 1,
} }
fn process(data: &str) -> u64 { const ARRAY_SIZE: usize = 15;
let mut answer = 0;
fn process(data: &[u8]) -> u64 {
let mut answer = 0;
let mut cards = vec![]; let mut cards = vec![];
for data in data.lines() { for data in data.split(|&x| x == b'\n') {
if data.is_empty() { if data.is_empty() {
continue; continue;
} }
let (card, value) = data.split_at(6); let (card, value) = data.split_at(6);
let card = card.trim(); let card = card.trim_ascii();
let mut arr = [0; 255]; let mut arr = [0; ARRAY_SIZE];
for c in card.bytes() { for &c in card {
let c = card_weight(c);
arr[c as usize] += 1; arr[c as usize] += 1;
} }
let transposed = transpose(&arr);
let ttype = if arr.iter().any(|&x| x == 5) { let set_type = match transposed {
SetType::Five [_, _, _, _, _, 1] => SetType::Five,
} else if arr.iter().any(|&x| x == 4) && arr.iter().any(|&x| x == 1) {
SetType::Four [_, 1, _, _, 1, _] => SetType::Four,
} else if arr.iter().any(|&x| x == 3) && arr.iter().any(|&x| x == 2) {
SetType::FullHouse [_, _, 1, 1, _, _] => SetType::FullHouse,
} else if arr.iter().any(|&x| x == 3) && arr.iter().filter(|&&x| x == 1).count() == 2 {
SetType::Three [_, 2, _, 1, _, _] => SetType::Three,
} else if arr.iter().filter(|&&x| x == 2).count() == 2
&& arr.iter().filter(|&&x| x == 1).count() == 1 [_, 1, 2, _, _, _] => SetType::Two,
{
SetType::Two [_, 3, 1, _, _, _] => SetType::One,
} else if arr.iter().filter(|&&x| x == 2).count() == 1
&& arr.iter().filter(|&&x| x == 1).count() == 3 [_, 5, _, _, _, _] => SetType::High,
{
SetType::One _ => unreachable!(),
} else if arr.iter().all(|&x| x == 0 || x == 1) {
SetType::High
} else {
unreachable!()
}; };
let mut num = 0;
let mut pow = 1;
for &val in value.iter().rev() {
num += (val - b'0') as u64 * pow;
pow *= 10;
}
cards.push(( cards.push((
Card { Card {
val: card.to_string(), val: card,
ttype, set_type,
}, },
value, num,
)); ));
} }
cards.sort_unstable_by(|(a, _), (b, _)| match (a.ttype, b.ttype) { cards.sort_unstable_by(|(a, _), (b, _)| match (a.set_type, b.set_type) {
(x, y) if x == y => { (x, y) if x == y => {
for (a, b) in a.val.chars().zip(b.val.chars()) { for (a, b) in a.val.iter().zip(b.val.iter()) {
let ordering = cmp(a, b); let ordering = cmp(*a, *b);
if ordering != Ordering::Equal { if ordering != Ordering::Equal {
return ordering; return ordering;
@ -93,7 +104,6 @@ fn process(data: &str) -> u64 {
}); });
for (i, (_, v)) in cards.into_iter().enumerate() { for (i, (_, v)) in cards.into_iter().enumerate() {
let v = v.parse::<u64>().unwrap();
let i = i + 1; let i = i + 1;
answer += v * i as u64; answer += v * i as u64;
@ -102,55 +112,82 @@ fn process(data: &str) -> u64 {
answer answer
} }
fn cmp(a: char, b: char) -> Ordering { #[inline]
if let Ordering::Equal = a.cmp(&b) { const fn cmp(a: u8, b: u8) -> Ordering {
if a == b {
return Ordering::Equal; return Ordering::Equal;
} }
match (a, b) { match (a, b) {
('A', _) => Ordering::Greater, (b'A', _) => Ordering::Greater,
(_, 'A') => Ordering::Less, (_, b'A') => Ordering::Less,
('K', _) => Ordering::Greater, (b'K', _) => Ordering::Greater,
(_, 'K') => Ordering::Less, (_, b'K') => Ordering::Less,
('Q', _) => Ordering::Greater, (b'Q', _) => Ordering::Greater,
(_, 'Q') => Ordering::Less, (_, b'Q') => Ordering::Less,
('J', _) => Ordering::Greater, (b'J', _) => Ordering::Greater,
(_, 'J') => Ordering::Less, (_, b'J') => Ordering::Less,
('T', _) => Ordering::Greater, (b'T', _) => Ordering::Greater,
(_, 'T') => Ordering::Less, (_, b'T') => Ordering::Less,
('9', _) => Ordering::Greater, (b'9', _) => Ordering::Greater,
(_, '9') => Ordering::Less, (_, b'9') => Ordering::Less,
('8', _) => Ordering::Greater, (b'8', _) => Ordering::Greater,
(_, '8') => Ordering::Less, (_, b'8') => Ordering::Less,
('7', _) => Ordering::Greater, (b'7', _) => Ordering::Greater,
(_, '7') => Ordering::Less, (_, b'7') => Ordering::Less,
('6', _) => Ordering::Greater, (b'6', _) => Ordering::Greater,
(_, '6') => Ordering::Less, (_, b'6') => Ordering::Less,
('5', _) => Ordering::Greater, (b'5', _) => Ordering::Greater,
(_, '5') => Ordering::Less, (_, b'5') => Ordering::Less,
('4', _) => Ordering::Greater, (b'4', _) => Ordering::Greater,
(_, '4') => Ordering::Less, (_, b'4') => Ordering::Less,
('3', _) => Ordering::Greater, (b'3', _) => Ordering::Greater,
(_, '3') => Ordering::Less, (_, b'3') => Ordering::Less,
('2', _) => Ordering::Greater, (b'2', _) => Ordering::Greater,
(_, '2') => Ordering::Less, (_, b'2') => Ordering::Less,
(_, _) => unreachable!(), (_, _) => unreachable!(),
} }
} }
#[inline]
fn transpose(ip: &[u8; ARRAY_SIZE]) -> [u8; 6] {
let mut out = [0; 6];
for &v in ip {
out[v as usize] += 1;
}
out
}
#[inline]
const fn card_weight(a: u8) -> u8 {
match a {
b'2'..=b'9' => a - b'0',
b'J' => 10,
b'T' => 11,
b'Q' => 12,
b'K' => 13,
b'A' => 14,
_ => 0,
}
}
fn main() { fn main() {
for input in INPUTS.iter() { for input in INPUTS.iter() {
println!("total = {}", process(input)); println!("total = {}", process(input));
@ -158,7 +195,7 @@ fn main() {
} }
#[bench] #[bench]
fn part2(b: &mut test::Bencher) { fn part1(b: &mut test::Bencher) {
b.iter(|| { b.iter(|| {
let v = process(INPUTS[1]); let v = process(INPUTS[1]);
test::black_box(v); test::black_box(v);

View File

@ -1,15 +1,19 @@
#![feature(byte_slice_trim_ascii)]
#![feature(test)] #![feature(test)]
use std::cmp::Ordering; use std::cmp::Ordering;
extern crate test; extern crate test;
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")]; const INPUTS: [&[u8]; 2] = [
include_bytes!("./sample.txt"),
include_bytes!("./input.txt"),
];
#[derive(Debug)] #[derive(Debug)]
struct Card { struct Card<'a> {
val: String, val: &'a [u8],
ttype: SetType, ctype: SetType,
} }
#[derive(Debug, Eq, PartialEq, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Clone, Copy)]
@ -23,85 +27,74 @@ enum SetType {
High = 1, High = 1,
} }
fn process(data: &str) -> u64 { const ARRAY_SIZE: usize = 14;
fn process(data: &[u8]) -> u64 {
let mut answer = 0; let mut answer = 0;
let mut cards = vec![]; let mut cards = vec![];
for data in data.lines() { for data in data.split(|&x| x == b'\n') {
if data.is_empty() { if data.is_empty() {
continue; continue;
} }
let (card, value) = data.split_at(6); let (card, value) = data.split_at(6);
let card = card.trim(); let card = card.trim_ascii();
let mut arr = [0; 255]; let mut arr = [0; ARRAY_SIZE];
for c in card.bytes() { for &c in card.iter() {
let c = card_weight(c);
arr[c as usize] += 1; arr[c as usize] += 1;
} }
let count = arr['J' as u8 as usize];
let ttype = if arr.iter().any(|&x| x == 5) { let count = arr[card_weight(b'J') as usize];
SetType::Five let transposed = transpose(&arr);
} else if arr.iter().any(|&x| x == 4) && arr.iter().any(|&x| x == 1) {
if count == 4 || count == 1 { let ctype = match (count, transposed) {
SetType::Five (_, [_, _, _, _, _, 1]) => SetType::Five,
} else {
SetType::Four (4, [_, 1, _, _, 1, _]) => SetType::Five,
} (1, [_, 1, _, _, 1, _]) => SetType::Five,
} else if arr.iter().any(|&x| x == 3) && arr.iter().any(|&x| x == 2) { (_, [_, 1, _, _, 1, _]) => SetType::Four,
if count == 3 || count == 2 {
SetType::Five (3, [_, _, 1, 1, _, _]) => SetType::Five,
} else { (2, [_, _, 1, 1, _, _]) => SetType::Five,
SetType::FullHouse (_, [_, _, 1, 1, _, _]) => SetType::FullHouse,
}
} else if arr.iter().any(|&x| x == 3) && arr.iter().filter(|&&x| x == 1).count() == 2 { (3, [_, 2, _, 1, _, _]) => SetType::Four,
if count == 3 || count == 1 { (1, [_, 2, _, 1, _, _]) => SetType::Four,
SetType::Four (_, [_, 2, _, 1, _, _]) => SetType::Three,
} else {
SetType::Three (2, [_, 1, 2, _, _, _]) => SetType::Four,
} (1, [_, 1, 2, _, _, _]) => SetType::FullHouse,
} else if arr.iter().filter(|&&x| x == 2).count() == 2 (_, [_, 1, 2, _, _, _]) => SetType::Two,
&& arr.iter().filter(|&&x| x == 1).count() == 1
{ (2, [_, 3, 1, _, _, _]) => SetType::Three,
if count == 2 { (1, [_, 3, 1, _, _, _]) => SetType::Three,
SetType::Four (_, [_, 3, 1, _, _, _]) => SetType::One,
} else if count == 1 {
SetType::FullHouse (1, [_, 5, _, _, _, _]) => SetType::One,
} else { (_, [_, 5, _, _, _, _]) => SetType::High,
SetType::Two
} (_, _) => unreachable!(),
} else if arr.iter().filter(|&&x| x == 2).count() == 1
&& arr.iter().filter(|&&x| x == 1).count() == 3
{
if count == 2 || count == 1 {
SetType::Three
} else {
SetType::One
}
} else if arr.iter().all(|&x| x == 0 || x == 1) {
if count == 1 {
SetType::One
} else {
SetType::High
}
} else {
unreachable!()
}; };
cards.push(( let mut num = 0;
Card { let mut pow = 1;
val: card.to_string(),
ttype, for &val in value.iter().rev() {
}, num += (val - b'0') as u64 * pow;
value.parse::<u64>().unwrap(), pow *= 10;
));
} }
cards.sort_unstable_by(|(a, _), (b, _)| match (a.ttype, b.ttype) {
cards.push((Card { val: card, ctype }, num));
}
cards.sort_unstable_by(|(a, _), (b, _)| match (a.ctype, b.ctype) {
(x, y) if x == y => { (x, y) if x == y => {
for (a, b) in a.val.chars().zip(b.val.chars()) { for (a, b) in a.val.iter().zip(b.val.iter()) {
let ordering = cmp(a, b); let ordering = cmp(*a, *b);
if ordering != Ordering::Equal { if ordering != Ordering::Equal {
return ordering; return ordering;
@ -127,50 +120,78 @@ fn process(data: &str) -> u64 {
answer answer
} }
fn cmp(a: char, b: char) -> Ordering { #[inline]
if let Ordering::Equal = a.cmp(&b) { fn transpose(ip: &[u8; ARRAY_SIZE]) -> [u8; 6] {
let mut out = [0; 6];
for &v in ip {
out[v as usize] += 1;
}
out
}
#[inline]
const fn card_weight(a: u8) -> u8 {
match a {
b'J' => 1,
b'2'..=b'9' => a - b'0',
b'T' => 10,
b'Q' => 11,
b'K' => 12,
b'A' => 13,
_ => 0,
}
}
#[inline]
const fn cmp(a: u8, b: u8) -> Ordering {
if a == b {
return Ordering::Equal; return Ordering::Equal;
} }
match (a, b) { match (a, b) {
('A', _) => Ordering::Greater, (b'A', _) => Ordering::Greater,
(_, 'A') => Ordering::Less, (_, b'A') => Ordering::Less,
('K', _) => Ordering::Greater, (b'K', _) => Ordering::Greater,
(_, 'K') => Ordering::Less, (_, b'K') => Ordering::Less,
('Q', _) => Ordering::Greater, (b'Q', _) => Ordering::Greater,
(_, 'Q') => Ordering::Less, (_, b'Q') => Ordering::Less,
('T', _) => Ordering::Greater, (b'T', _) => Ordering::Greater,
(_, 'T') => Ordering::Less, (_, b'T') => Ordering::Less,
('9', _) => Ordering::Greater, (b'9', _) => Ordering::Greater,
(_, '9') => Ordering::Less, (_, b'9') => Ordering::Less,
('8', _) => Ordering::Greater, (b'8', _) => Ordering::Greater,
(_, '8') => Ordering::Less, (_, b'8') => Ordering::Less,
('7', _) => Ordering::Greater, (b'7', _) => Ordering::Greater,
(_, '7') => Ordering::Less, (_, b'7') => Ordering::Less,
('6', _) => Ordering::Greater, (b'6', _) => Ordering::Greater,
(_, '6') => Ordering::Less, (_, b'6') => Ordering::Less,
('5', _) => Ordering::Greater, (b'5', _) => Ordering::Greater,
(_, '5') => Ordering::Less, (_, b'5') => Ordering::Less,
('4', _) => Ordering::Greater, (b'4', _) => Ordering::Greater,
(_, '4') => Ordering::Less, (_, b'4') => Ordering::Less,
('3', _) => Ordering::Greater, (b'3', _) => Ordering::Greater,
(_, '3') => Ordering::Less, (_, b'3') => Ordering::Less,
('2', _) => Ordering::Greater, (b'2', _) => Ordering::Greater,
(_, '2') => Ordering::Less, (_, b'2') => Ordering::Less,
('J', _) => Ordering::Greater, (b'J', _) => Ordering::Greater,
(_, 'J') => Ordering::Less, (_, b'J') => Ordering::Less,
(_, _) => unreachable!(), (_, _) => unreachable!(),
} }