|
|
@@ -0,0 +1,149 @@
|
|
|
+use std::fs;
|
|
|
+use std::env;
|
|
|
+use std::cmp::max;
|
|
|
+
|
|
|
+use nom::IResult;
|
|
|
+use nom::character::complete::char;
|
|
|
+use nom::combinator::value;
|
|
|
+use nom::branch::alt;
|
|
|
+use nom::multi::many1;
|
|
|
+use nom::sequence::separated_pair;
|
|
|
+use nom::character::complete::space1;
|
|
|
+use nom::character::complete::i64;
|
|
|
+use nom::combinator::map;
|
|
|
+
|
|
|
+#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
+struct Hand {
|
|
|
+ cards: Vec<i32>,
|
|
|
+ cached_strength: Option<i32>,
|
|
|
+}
|
|
|
+
|
|
|
+fn hand_strength(cards: &Vec<i32>) -> i32 {
|
|
|
+ let mut kinds: [i32; 15] = [0; 15];
|
|
|
+ for c in cards {
|
|
|
+ kinds[*c as usize] += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // descending sort
|
|
|
+ kinds.sort_by(|a, b|b.cmp(a));
|
|
|
+ if kinds[0] == 5 {
|
|
|
+ return 6;
|
|
|
+ } else if kinds[0] == 4 {
|
|
|
+ return 5;
|
|
|
+ } else if kinds[0] == 3 && kinds[1] == 2 {
|
|
|
+ return 4;
|
|
|
+ } else if kinds[0] == 3 {
|
|
|
+ return 3;
|
|
|
+ } else if kinds[0] == 2 && kinds[1] == 2 {
|
|
|
+ return 2;
|
|
|
+ } else if kinds[0] == 2 {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ 0
|
|
|
+}
|
|
|
+
|
|
|
+impl Hand {
|
|
|
+ fn strength(&mut self) -> i32 {
|
|
|
+ if self.cached_strength.is_some() {
|
|
|
+ return self.cached_strength.unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut joker_indices = Vec::new();
|
|
|
+ for i in 0..self.cards.len() {
|
|
|
+ if self.cards[i] == 0 {
|
|
|
+ joker_indices.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut hands = vec![self.cards.clone()];
|
|
|
+ for joker_index in joker_indices {
|
|
|
+ let mut next_hands = Vec::new();
|
|
|
+ for hand in &hands {
|
|
|
+ for card in 0..13 {
|
|
|
+ let mut next_hand = hand.clone();
|
|
|
+ next_hand[joker_index] = card;
|
|
|
+ next_hands.push(next_hand);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ hands = next_hands;
|
|
|
+ }
|
|
|
+
|
|
|
+ self.cached_strength = Some(hands.into_iter().map(|h|hand_strength(&h)).fold(0, |acc, s| max(acc, s)));
|
|
|
+ self.cached_strength.unwrap()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn parse_card(input: &str) -> IResult<&str, i32> {
|
|
|
+ alt((
|
|
|
+ value(0, char('J')),
|
|
|
+ value(1, char('2')),
|
|
|
+ value(2, char('3')),
|
|
|
+ value(3, char('4')),
|
|
|
+ value(4, char('5')),
|
|
|
+ value(5, char('6')),
|
|
|
+ value(6, char('7')),
|
|
|
+ value(7, char('8')),
|
|
|
+ value(8, char('9')),
|
|
|
+ value(9, char('T')),
|
|
|
+ value(10, char('Q')),
|
|
|
+ value(11, char('K')),
|
|
|
+ value(12, char('A')),
|
|
|
+ ))(input)
|
|
|
+}
|
|
|
+
|
|
|
+fn parse_hand(input: &str) -> IResult<&str, Hand> {
|
|
|
+ map(many1(parse_card), |cards:Vec<i32>| Hand{cards, cached_strength:None})(input)
|
|
|
+}
|
|
|
+
|
|
|
+fn parse_hand_and_bid(input: &str) -> IResult<&str, (Hand, i64)> {
|
|
|
+ separated_pair(parse_hand, space1, i64)(input)
|
|
|
+}
|
|
|
+
|
|
|
+fn parse_line(input: &str) -> Result<(Hand, i64), String> {
|
|
|
+ match parse_hand_and_bid(input) {
|
|
|
+ Ok((rest, data)) => if rest == "" {
|
|
|
+ Ok(data)
|
|
|
+ } else {
|
|
|
+ Err(format!("Incomplete parse, remaining: {}", rest))
|
|
|
+ },
|
|
|
+ Err(error) => Err(error.to_string()),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ let args: Vec<String> = env::args().collect();
|
|
|
+ let file_path = &args[1];
|
|
|
+ let input_data = fs::read_to_string(file_path).unwrap_or_else(
|
|
|
+ |_|{panic!("Can't read file {}", file_path)});
|
|
|
+
|
|
|
+ let mut order:Vec<usize> = Vec::new();
|
|
|
+ let mut hands_and_bids = Vec::new();
|
|
|
+
|
|
|
+ let mut offset:usize = 0;
|
|
|
+ for line in input_data.lines() {
|
|
|
+ let hand_and_bid = parse_line(line).unwrap_or_else(
|
|
|
+ |e|panic!("Failed to parse line: {}", e));
|
|
|
+
|
|
|
+ hands_and_bids.push(hand_and_bid);
|
|
|
+ order.push(offset);
|
|
|
+ offset += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ order.sort_by(|a,b|{
|
|
|
+ let sa = hands_and_bids[*a].0.strength();
|
|
|
+ let sb = hands_and_bids[*b].0.strength();
|
|
|
+ if sa == sb {
|
|
|
+ hands_and_bids[*a].0.cards.cmp(&hands_and_bids[*b].0.cards)
|
|
|
+ } else {
|
|
|
+ sa.cmp(&sb)
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ let mut result:i64 = 0;
|
|
|
+ for i in 0..order.len() {
|
|
|
+ result += hands_and_bids[order[i]].1 * (i+1) as i64;
|
|
|
+ }
|
|
|
+ println!("{result}");
|
|
|
+}
|