Advent of Rust // Day 2

The second day was still easy on the puzzle side. I guess I went a little overboard with the implementation, but I wanted to play with the language. I had a lot of first ones today: First struct, first enum, first use of impl to add functionality, passing functions as arguments, and adding behavior with derivable traits. I wish I could say that I’m fully aware of everything I’m doing; there’s still a good amount of trial and error.

extern crate core;

use std::fs;

use itertools::Itertools;

struct Input {
    player: String,
    opponent: String,
}

struct Game {
    player: Shape,
    opponent: Shape,
}

#[derive(PartialEq, Clone, Copy)]
enum Shape {
    Rock,
    Paper,
    Scissors,
}

impl Shape {
    fn wins_against(&self) -> Shape {
        return match *self {
            Shape::Rock => Shape::Scissors,
            Shape::Paper => Shape::Rock,
            Shape::Scissors => Shape::Paper,
        };
    }

    fn loses_against(&self) -> Shape {
        return match *self {
            Shape::Scissors => Shape::Rock,
            Shape::Rock => Shape::Paper,
            Shape::Paper => Shape::Scissors,
        };
    }
}

fn game_from_input_for_part_one(input: &Input) -> Game {
    let opponent = match input.opponent.as_str() {
        "A" => Shape::Rock,
        "B" => Shape::Paper,
        "C" => Shape::Scissors,
        _ => panic!("Invalid value {}", input.opponent)
    };

    let player = match input.player.as_str() {
        "X" => Shape::Rock,
        "Y" => Shape::Paper,
        "Z" => Shape::Scissors,
        _ => panic!("Invalid value {}", input.player)
    };

    return Game { opponent, player };
}

fn game_from_input_for_part_two(input: &Input) -> Game {
    let opponent = match input.opponent.as_str() {
        "A" => Shape::Rock,
        "B" => Shape::Paper,
        "C" => Shape::Scissors,
        _ => panic!("Invalid value {}", input.opponent)
    };

    let player = match input.player.as_str() {
        "X" => opponent.wins_against(),
        "Y" => opponent,
        "Z" => opponent.loses_against(),
        _ => panic!("Invalid value {}", input.player)
    };

    return Game { opponent, player };
}

fn player_score(game: &Game) -> u16 {
    let points = match game.player {
        Shape::Rock => 1,
        Shape::Paper => 2,
        Shape::Scissors => 3,
    };

    if game.player == game.opponent {
        return points + 3;
    }

    if game.player.wins_against() == game.opponent {
        return points + 6;
    }

    return points;
}

fn player_total_score(games: Vec<Game>) -> u16 {
    return games.iter().map(player_score).sum();
}

fn map_input(input: &Vec<Input>, callback: fn(&Input) -> Game) -> Vec<Game> {
    return input.iter().map(callback).collect_vec();
}

fn main() {
    let input = fs::read_to_string("input/day02.txt")
        .unwrap()
        .lines()
        .map(|line| {
            let (opponent, player) = line.split_once(' ').unwrap();

            return Input { opponent: String::from(opponent), player: String::from(player) };
        })
        .collect_vec();

    println!("Part One: {}", player_total_score(map_input(&input, game_from_input_for_part_one)));
    println!("Part Two: {}", player_total_score(map_input(&input, game_from_input_for_part_two)));
}

My solutions for the others puzzles of Advent of Code can be found below and in my GitHub repository.

See also in Advent of Rust

Comments

You can leave a comment by replying to this post on Mastodon.