diff --git a/08_Batnum/perl/README.md b/08_Batnum/perl/README.md index e69c8b81..8e05356a 100644 --- a/08_Batnum/perl/README.md +++ b/08_Batnum/perl/README.md @@ -1,3 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Perl](https://www.perl.org/) +Conversion to [Perl](https://www.perl.org/) by [Austin White](https://github.com/austinwhite) diff --git a/08_Batnum/perl/batnum.pl b/08_Batnum/perl/batnum.pl new file mode 100644 index 00000000..4280bf38 --- /dev/null +++ b/08_Batnum/perl/batnum.pl @@ -0,0 +1,268 @@ +use strict; +use warnings; + +my %WIN_OPTIONS = ( + "UNDEFINED" => 0, + "TAKE_LAST" => 1, + "AVOID_LAST" => 2, +); + +my %START_OPTIONS = ( + "UNDEFINED" => 0, + "COMPUTER_FIRST" => 1, + "PLAYER_FIRST" => 2, +); + + +sub run { + # input: no input perameters + # + # output: nothing returned + # + # description: This is the primary game loop. Once a game is concluded + # another will begin right away until the exeecution + # is terminated. + + my $pile_size = undef; + my $min_select = undef; + my $max_select = undef; + my $win_option = undef; + my $start_option = undef; + + while (1) { + write_intro(); + + ($pile_size, $min_select, $max_select, $win_option, $start_option) + = &get_user_input(); + + play($pile_size, $min_select, $max_select, $win_option, $start_option); + + printf "\n"; + } +} + + +sub write_intro { + # input: no input perameters + # + # output: nothing returned + # + # description: This subroutine prints the intro and rules. + + printf "%33s", "BATNUM\n"; + printf "%15s", "CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY\n"; + printf "%s", "\n"; + printf "%s", "\n"; + printf "%s", "\n"; + printf "%s", "THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\n"; + printf "%s", "COMPUTER IS YOUR OPPONENT.\n"; + printf "%s", "\n"; + printf "%s", "THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\n"; + printf "%s", "AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\n"; + printf "%s", "WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\n"; + printf "%s", "NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\n"; + printf "%s", "DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\n"; + printf "%s", "ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\n"; + printf "%s", "\n"; +} + + +sub get_user_input { + # input: no input perameters + # + # output: (int) pile_size + # (int) min_select + # (int) max_select + # (int) win_option + # (int) start_option + # + # description: This subroutine gets the necessary perametes from the player. + # + # pile_size (int > 0) + # min_select (int > 0) max_select (int > 0) + # -> min/max, space delimated + # win_option (int 1|2) + # start_option (int 1|2) + + my $pile_size = 0; + my $min_select = 0; + my $max_select = 0; + my $win_option = $WIN_OPTIONS{ "UNDEFINED" }; + my $start_option = $START_OPTIONS{ "UNDEFINED" }; + + while ($pile_size < 1) { + printf "%s", "ENTER PILE SIZE: "; + $pile_size = ; + } + + while ($min_select < 1 || $max_select < 1 || $min_select > $max_select) { + printf "%s", "ENTER MIN AND MAX: "; + my $raw_input = ; + ($min_select, $max_select) = split(' ', $raw_input); + } + + while ($win_option eq $WIN_OPTIONS{ "UNDEFINED" }) { + printf "%s", "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: "; + $win_option = ; + } + + while ($start_option eq $START_OPTIONS{ "UNDEFINED" }) { + printf "%s", "ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST: "; + $start_option = ; + } + + return ($pile_size, $min_select, $max_select, $win_option, $start_option); +} + + +sub play { + # input: (int) pile_size + # (int) min_select + # (int) max_select + # (int) win_option + # (int) start_option + # + # output: nothing returned + # + # description: This is where the game logic lives. The player and computer + # both take turns until the current game is over. + + my $pile_size = shift; + my $min_select = shift; + my $max_select = shift; + my $win_option = shift; + my $start_option = shift; + + my $game_over = 0; + my $players_turn = $start_option eq $START_OPTIONS{ "PLAYER_FIRST" } ? 1 : 0; + + while (!$game_over) { + if ($players_turn) { + ($game_over, $pile_size) = players_move( + $pile_size, $min_select, $max_select, $win_option); + + $players_turn = 0; + + if ($game_over) { + return; + } + } else { + ($game_over, $pile_size) = computers_move( + $pile_size, $min_select, $max_select, $win_option); + + $players_turn = 1; + } + } + + return; +} + + +sub players_move { + # input: (int) pile_size + # (int) min_select + # (int) max_select + # (int) win_option + # + # output: (boolean) game is over + # (int) new pile_size + # + # description: This subroutine handles the players move. + + my $pile_size = shift; + my $min_select = shift; + my $max_select = shift; + my $win_option = shift; + + my $finished = 0; + + while (!$finished) { + my $remove_amount = undef; + + printf "%s", "YOUR MOVE: "; + $remove_amount = <>; + + if ($remove_amount eq 0) { + printf "%s", "I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT."; + return (1, $pile_size); + } elsif ($remove_amount > $max_select || $remove_amount < $min_select) { + printf "%s", "ILLEGAL MOVE, TRY AGAIN.\n"; + next; + } else { + $pile_size -= $remove_amount; + $finished = 1; + } + + if ($pile_size <= 0) { + if ($win_option eq $WIN_OPTIONS{ "AVOID_LAST" }) { + printf "%s", "TOUGH LUCK, YOU LOSE.\n"; + } else { + printf "%s", "CONGRATULATIONS, YOU WIN.\n"; + } + return (1, $pile_size); + } + } + + return (0, $pile_size); +} + + +sub computers_move { + # input: (int) pile_size + # (int) min_select + # (int) max_select + # (int) win_option + # + # output: (boolean) game is over + # (int) new pile_size + # + # description: This subroutine handles the computers move. + + my $pile_size = shift; + my $min_select = shift; + my $max_select = shift; + my $win_option = shift; + + if ($win_option eq $WIN_OPTIONS{ "TAKE_LAST" } && $pile_size <= $max_select) { + printf "COMPUTER TAKES %d AND WINS.\n", $pile_size; + return (1, $pile_size); + } + + if ($win_option eq $WIN_OPTIONS{ "AVOID_LAST" } && $pile_size <= $min_select) { + printf "COMPUTER TAKES %d AND LOSES.\n", $pile_size; + return (1, $pile_size); + } + + my $remove_amount = get_computer_remove_amount($min_select, $max_select); + + $pile_size -= $remove_amount; + + if ($pile_size <= 0) { + printf "COMPUTER TAKES %d AND WINS.\n", $remove_amount; + return (1, $pile_size); + } else { + printf "COMPUTER TAKES %d AND LEAVES %d.\n", $remove_amount, $pile_size; + } + + return (0, $pile_size); +} + + +sub get_computer_remove_amount { + # input: (int) min_select + # (int) max_select + # + # output: (int) random number (x) where, + # min_select <= x <= max_select + # + # description: This subroutine generates the amount of items the computer + # will remove. + + my $min_select = shift; + my $max_select = shift; + + return (int(rand($max_select - $min_select)) + $min_select); +} + +# start the game +run();