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)[0] )
}
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
}
}