From 06d2e664ad1bcd075fb1d1fc98d7ac824ac722dd Mon Sep 17 00:00:00 2001 From: wieerwill Date: Thu, 7 Dec 2023 19:49:14 +0100 Subject: [PATCH] update Readme to Day07 --- Day07/js/solution.js | 97 ++++++++++++++++++++++++++++++++++++++++++ Day07/rust/Cargo.toml | 8 ++++ Day07/rust/src/main.rs | 88 ++++++++++++++++++++++++++++++++++++++ README.md | 2 +- 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 Day07/js/solution.js create mode 100644 Day07/rust/Cargo.toml create mode 100644 Day07/rust/src/main.rs diff --git a/Day07/js/solution.js b/Day07/js/solution.js new file mode 100644 index 0000000..6d861a3 --- /dev/null +++ b/Day07/js/solution.js @@ -0,0 +1,97 @@ +const fs = require('fs'); + +function readHands(filePath) { + try { + const data = fs.readFileSync(filePath, 'utf-8'); + console.log(`Reading hands from ${filePath}...`); + return data.trim().split('\n').map(line => line.split(' ')); + } catch (err) { + console.error(`Error reading file ${filePath}: ${err}`); + throw err; + } +} + +function replaceFaceCards(hand) { + return hand.replace(/T/g, 'a') + .replace(/J/g, '1') + .replace(/Q/g, 'c') + .replace(/K/g, 'd') + .replace(/A/g, 'e'); +} + +function calculateStrength(hand) { + hand = replaceFaceCards(hand); + const counts = hand.split('').reduce((acc, card) => { + acc[card] = (acc[card] || 0) + 1; + return acc; + }, {}); + + if ('1' in counts) { + let maxCount = Math.max(...Object.values(counts)); + let maxCard = Object.keys(counts).find(card => counts[card] === maxCount && card !== '1'); + + if (maxCard) { + counts[maxCard] += counts['1']; + delete counts['1']; + } + } + + const sortedCounts = Object.values(counts).sort((a, b) => b - a); + + console.log(`Hand: ${hand}, Counts: ${sortedCounts}`); + + if (sortedCounts.toString() === '5') return 10; + if (sortedCounts.toString() === '1,4') return 9; + if (sortedCounts.toString() === '2,3') return 8; + if (sortedCounts.toString() === '1,1,3') return 7; + if (sortedCounts.toString() === '1,2,2') return 6; + if (sortedCounts.toString() === '1,1,1,2') return 5; + if (sortedCounts.toString() === '1,1,1,1,1') return 4; + + throw new Error(`Invalid hand: ${hand}, Counts: ${sortedCounts}`); +} + +function handKey(hand) { + return calculateStrength(hand[0]); +} + +function calculateTotalWinnings(filePath) { + try { + const hands = readHands(filePath); + console.log("Sorting hands based on strength..."); + hands.sort((a, b) => handKey(b) - handKey(a)); + + console.log("Calculating total winnings..."); + return hands.reduce((acc, [hand, bid], index) => { + const winnings = (index + 1) * parseInt(bid, 10); + console.log(`Hand: ${hand}, Rank: ${index + 1}, Bid: ${bid}, Winnings: ${winnings}`); + return acc + winnings; + }, 0); + } catch (err) { + console.error(`Error calculating winnings: ${err}`); + throw err; + } +} + +function runTest(filePath, expected) { + console.log(`Running test with ${filePath}...`); + try { + const totalWinnings = calculateTotalWinnings(filePath); + console.assert(totalWinnings === expected, `Test failed, expected ${expected} but got ${totalWinnings}`); + console.log(`Test passed: ${totalWinnings}`); + } catch (err) { + console.error(`Test failed: ${err}`); + } +} + +function main() { + try { + runTest("../test.txt", 5905); + const result = calculateTotalWinnings("../input.txt"); + console.log(`Total result from input.txt: ${result}`); + } catch (err) { + console.error(`An error occurred: ${err}`); + } +} + +main(); diff --git a/Day07/rust/Cargo.toml b/Day07/rust/Cargo.toml new file mode 100644 index 0000000..1ec6963 --- /dev/null +++ b/Day07/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/Day07/rust/src/main.rs b/Day07/rust/src/main.rs new file mode 100644 index 0000000..bd5841d --- /dev/null +++ b/Day07/rust/src/main.rs @@ -0,0 +1,88 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, BufRead}; + +fn read_hands(filename: &str) -> io::Result> { + let file = File::open(filename)?; + let lines = io::BufReader::new(file).lines(); + + let mut hands = Vec::new(); + for line in lines { + if let Ok(line) = line { + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() == 2 { + let hand = parts[0].to_string(); + let bid: i32 = parts[1].parse().unwrap(); + hands.push((hand, bid)); + } + } + } + Ok(hands) +} + +fn replace_face_cards(hand: &str) -> String { + let mut replaced = hand.to_string(); + replaced = replaced.replace("T", "a"); + replaced = replaced.replace("J", "1"); + replaced = replaced.replace("Q", "c"); + replaced = replaced.replace("K", "d"); + replaced = replaced.replace("A", "e"); + replaced +} + +fn calculate_strength(hand: &str) -> (i32, String) { + let replaced_hand = replace_face_cards(hand); + let mut counts = HashMap::new(); + for c in replaced_hand.chars() { + *counts.entry(c).or_insert(0) += 1; + } + + let mut joker_count = 0; + if counts.contains_key(&'1') { + joker_count = counts.remove(&'1').unwrap(); + } + + let mut best_category = 4; // Default to High card + for (card, count) in &counts { + let adjusted_count = if *card != '1' { count + joker_count } else { *count }; + best_category = best_category.max(match adjusted_count { + 5 => 10, + 4 => 9, + 3 if counts.values().any(|&v| v == 2) => 8, + 3 => 7, + _ => best_category, + }); + } + + // Use original hand for tie-breaking + let tie_breaker_hand = hand.chars().collect::(); + println!("Hand: {}, Strength: {}, Tie-breaker hand: {}", hand, best_category, tie_breaker_hand); + (best_category, tie_breaker_hand) +} + +fn calculate_total_winnings(hands: Vec<(String, i32)>) -> i32 { + let mut sorted_hands = hands; + // Sort based on strength and original hand for tie-breaking + sorted_hands.sort_unstable_by(|a, b| { + let (strength_a, tie_breaker_a) = calculate_strength(&a.0); + let (strength_b, tie_breaker_b) = calculate_strength(&b.0); + (strength_b, tie_breaker_b).cmp(&(strength_a, tie_breaker_a)) + }); + + sorted_hands.iter().enumerate().fold(0, |acc, (i, (hand, bid))| { + let winnings = bid * (i as i32 + 1); + println!("Hand: {}, Rank: {}, Bid: {}, Winnings: {}", hand, i + 1, bid, winnings); + acc + winnings + }) +} + +fn main() { + let test_hands = read_hands("../test.txt").expect("Failed to read test file"); + let test_total = calculate_total_winnings(test_hands); + assert_eq!(test_total, 5905, "Test failed: expected 5905, got {}", test_total); + println!("Test passed: Total winnings = {}", test_total); + + let hands = read_hands("../input.txt").expect("Failed to read input file"); + let total_winnings = calculate_total_winnings(hands); + println!("Total winnings from input.txt: {}", total_winnings); +} diff --git a/README.md b/README.md index b1797cf..3426940 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ I aim to complete each day's puzzle on the same day, but as with any challenge, | 04 | ✅ | ✅ | [Day04 README](/Day04/README.md) | | 05 | ✅ | ✅ | [Day05 README](/Day05/README.md) | | 06 | ✅ | ✅ | [Day06 README](/Day06/README.md) | -| 07 | ❓ | ❓ | [Day07 README](/Day07/README.md) | +| 07 | ✅ | ✅ | [Day07 README](/Day07/README.md) | | 08 | ❓ | ❓ | [Day08 README](/Day08/README.md) | | 09 | ❓ | ❓ | [Day09 README](/Day09/README.md) | | 10 | ❓ | ❓ | [Day10 README](/Day10/README.md) |