Skip to content

Instantly share code, notes, and snippets.

@0racle
Last active October 8, 2020 02:13
Embed
What would you like to do?
Rock Scissor Paper

An implementation of "Rock Scissor Paper" in Raku.

The "robot" will make a weighted random choice based on your previous moves.

use Term::ReadKey;
use Terminal::ANSIColor;

enum Choice  « :Rock(1) :Paper(2) :Scissors(3) »;
enum Outcome « :WIN(1)  :DRAW(0)  :LOSE(-1)    »;

my %colors = %(
    (WIN)  => 'green',
    (DRAW) => 'yellow',
    (LOSE) => 'red',
);

sub counter-attack(Choice $c --> Choice) {
    Choice( Choice.enums.values.sort.List.rotate($c) )
}

sub infix:<vs>(Choice $player, Choice $robot --> Outcome) {
    when $robot == counter-attack($player) { LOSE }
    when $robot == $player { DRAW }
    default { WIN }
}

sub get-choice(--> Choice) {
    loop {
        say "Choose your weapon { Choice.enums.sort(*.values).gist }";
        if Choice( read-key(:!echo) ) -> $c {
            return $c
        }
        say 'Invalid choice!'
    }
}

my $weights = BagHash.new: Choice.enums.values.map: -> $c { Choice($c) }
my %stats{Outcome};
my $score = 0;

loop {
    my $robot  = $weights.pick;
    my $player = get-choice();
    my $result = $player vs $robot;
    my $c-result = colored(~$result, %colors{$result});
    say "$player -VS- $robot".fmt('%-22s') => $c-result;
    $weights{ counter-attack($player) }++;
    $score += $result.value;
    %stats{$result}++;
    say "\n";
}

BEGIN {
    signal(SIGINT).tap: { say "\n" and exit }
}

END {
    if %stats {
        say qq:to<END>;
        Score: $score
        - Picks: { $weights.sort».gist.join(', ') }
        - Stats: { %stats.sort».gist.join(', ') }
        END
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment