Merge pull request #847 from kbrannen/07-basketball-perl

07 basketball perl
This commit is contained in:
Jeff Atwood
2023-04-20 14:02:56 -07:00
committed by GitHub
3 changed files with 826 additions and 0 deletions

View File

@@ -1,3 +1,21 @@
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) 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/)
There are two version of the code here, a "faithful" translation (basketball-orig.pl) and
a "modern" translation (basketball.pl). The main difference between the 2 are is that the
faithful translation has 3 GOTOs in it while the modern version has no GOTO. I have added
a "TIME" print when the score is shown so the Clock is visible. Halftime is at "50" and
end of game is at 100 (per the Basic code).
The 3 GOTOs in the faitful version are because of the way the original code jumped into
the "middle of logic" that has no obivious way to avoid ... that I can see, at least while
still maintaining something of the look and structure of the original Basic.
The modern version avoided the GOTOs by restructuring the program in the 2 "play()" subs.
Despite the change, this should play the same way as the faithful version.
All of the percentages remain the same. If writing this from scratch, we really should
have only a single play() sub which uses the same code for both teams, which would also
make the game more fair ... but that wasn't done so the percent edge to Darmouth has been
maintained here.

View File

@@ -0,0 +1,415 @@
#!/usr/bin/perl
# Basketball program in Perl
# This is fairly faithful translation from the original Basic.
# This becomes apparent because there are actually 3 GOTOs still present
# because of the way the original code jumped into the "middle of logic"
# that has no obivious way to avoid ... that I can see.
# For better structure and no GOTOs, see the other version of this program.
# Translated by Kevin Brannen (kbrannen)
use strict;
use warnings;
# globals
my $Defense=0; # dartmouth defense value
my $Opponent; # name of opponent
my @Score = (0, 0); # scores, dart is [0], opponent is [1]
my $Player = 0; # player, 0 = dart, 1 = opp
my $Timer = 0; # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93
my $DoPlay = 1; # true if game is still being played
my $ConTeam; # controlling team, "dart" or "opp"
my $ShotType = 0; # current shot type
print "\n";
print " " x 31, "BASKETBALL";
print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY";
print "\n\n\n";
print "THIS IS DARTMOUTH COLLEGE BASKETBALL. YOU WILL BE DARTMOUTH\n";
print "CAPTAIN AND PLAYMAKER. CALL SHOTS AS FOLLOWS:\n";
print " 1. LONG (30 FT.) JUMP SHOT;\n";
print " 2. SHORT (15 FT.) JUMP SHOT;\n";
print " 3. LAY UP;\n";
print " 4. SET SHOT.\n";
print "BOTH TEAMS WILL USE THE SAME DEFENSE. CALL DEFENSE AS FOLLOWS:\n";
print " 6. PRESS;\n";
print " 6.5 MAN-TO MAN;\n";
print " 7. ZONE;\n";
print " 7.5 NONE.\n";
print "TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\n\n";
get_defense();
print "\n";
print "CHOOSE YOUR OPPONENT: ";
chomp($Opponent = <>);
$ConTeam = center_jump();
while ($DoPlay)
{
print "\n";
if ($ConTeam eq "dart")
{
$Player = 0;
get_your_shot();
dartmouth_play();
}
else
{
opponent_play();
}
if ($Timer >= 100)
{
check_end_game();
last if (!$DoPlay);
$Timer = 93;
$ConTeam = center_jump();
}
}
exit(0);
###############################################################
sub dartmouth_play
{
if ($ShotType == 1 || $ShotType == 2)
{
$Timer++;
if ($Timer == 50)
{
end_first_half();
return;
}
if ($Timer == 92)
{
two_min_left();
}
print "JUMP SHOT\n";
if (rand(1) <= 0.341 * $Defense / 8)
{
print "SHOT IS GOOD.\n";
dartmouth_score();
$ConTeam = "opp";
return;
}
if (rand(1) <= 0.682*$Defense/8)
{
print "SHOT IS OFF TARGET.\n";
if ($Defense/6*rand(1) > 0.45)
{
print "REBOUND TO ", $Opponent, "\n";
$ConTeam = "opp";
return;
}
print "DARTMOUTH CONTROLS THE REBOUND.\n";
if (rand(1) <= 0.4) { goto L1300; }
if ($Defense == 6)
{
if (rand(1) <= 0.6)
{
print "PASS STOLEN BY $Opponent, EASY LAYUP.\n";
opp_score();
$ConTeam = "dart"; return;
return;
}
}
print "BALL PASSED BACK TO YOU.\n";
$ConTeam = "dart";
return;
}
if (rand(1) <= 0.782*$Defense/8)
{
print "SHOT IS BLOCKED. BALL CONTROLLED BY "; # no NL
if (rand(1) > 0.5)
{
print "$Opponent.\n";
$ConTeam = "opp";
return;
}
else
{
print "DARTMOUTH.\n";
$ConTeam = "dart";
return;
}
}
if (rand(1) > 0.843*$Defense/8)
{
print "CHARGING FOUL. DARTMOUTH LOSES BALL.\n";
$ConTeam = "opp";
return;
}
else
{
print "SHOOTER IS FOULED. TWO SHOTS.\n";
foul_shooting();
$ConTeam = "opp";
return;
}
}
L1300:
while (1)
{
$Timer++;
if ($Timer == 50)
{
end_first_half();
return;
}
if ($Timer == 92) { two_min_left(); }
if ($ShotType == 0)
{
get_defense();
return;
}
print '', ($ShotType > 3 ? "SET SHOT." : "LAY UP."), "\n";
if (7 / $Defense * rand(1) <= 0.4)
{
print "SHOT IS GOOD. TWO POINTS.\n";
dartmouth_score();
$ConTeam = "opp";
return;
}
if (7 / $Defense * rand(1) <= 0.7)
{
print "SHOT IS OFF THE RIM.\n";
if (rand(1) <= 0.667)
{
print "$Opponent CONTROLS THE REBOUND.\n";
$ConTeam = "opp";
return;
}
print "DARTMOUTH CONTROLS THE REBOUND.\n";
next if (rand(1) <= 0.4);
print "BALL PASSED BACK TO YOU.\n";
$ConTeam = "dart";
return;
}
if (7 / $Defense * rand(1) <= 0.875)
{
print "SHOOTER FOULED. TWO SHOTS.\n";
foul_shooting();
$ConTeam = "opp";
return;
}
if (7 / $Defense * rand(1) <= 0.925)
{
print "SHOT BLOCKED. $Opponent\'S BALL.\n";
$ConTeam = "opp";
return;
}
print "CHARGING FOUL. DARTMOUTH LOSES THE BALL.\n";
$ConTeam = "opp";
return;
}
}
sub get_defense
{
$Defense = 0;
while ($Defense < 6 || $Defense > 7.5)
{
print "YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): ";
chomp($Defense = <>);
($Defense) =~ m/(\d(\.\d)?)/;
}
}
sub opponent_play
{
$Player = 1;
$Timer++;
if ($Timer == 50)
{
end_first_half();
$ConTeam = center_jump();
return;
}
print "\n";
while (1)
{
my $shot = 10.0 / 4 * rand(1) + 1;
if ($shot <= 2.0)
{
print "JUMP SHOT.\n";
if (8.0 / $Defense * rand(1) <= 0.35)
{
print "SHOT IS GOOD.\n";
opp_score();
$ConTeam = "dart";
return;
}
if (8.0 / $Defense * rand(1) <= 0.75)
{
print "SHOT IS OFF RIM.\n";
L3110:
if ($Defense / 6.0 * rand(1) <= 0.5)
{
print "DARTMOUTH CONTROLS THE REBOUND.\n";
$ConTeam = "dart";
return;
}
print "$Opponent CONTROLS THE REBOUND.\n";
if ($Defense == 6)
{
if (rand(1) <= 0.75)
{
print "BALL STOLEN. EASY LAY UP FOR DARTMOUTH.\n";
dartmouth_score();
$ConTeam = "opp";
return;
}
}
if (rand(1) <= 0.5)
{
print "PASS BACK TO $Opponent GUARD.\n";
$ConTeam = "opp";
return;
}
goto L3500;
}
if (8.0 / $Defense * rand(1) <= 0.9)
{
print "PLAYER FOULED. TWO SHOTS.\n";
foul_shooting();
$ConTeam = "dart";
return;
}
print "OFFENSIVE FOUL. DARTMOUTH'S BALL.\n";
$ConTeam = "dart";
return;
}
L3500:
print ($shot > 3 ? "SET SHOT.\n" : "LAY UP.\n");
if (7.0 / $Defense * rand(1) > 0.413)
{
print "SHOT IS MISSED.\n";
{
no warnings;
goto L3110;
}
}
else
{
print "SHOT IS GOOD.\n";
opp_score();
$ConTeam = "dart";
return;
}
}
}
sub opp_score
{
$Score[0] += 2;
print_score();
}
sub dartmouth_score
{
$Score[1] += 2;
print_score();
}
sub print_score
{
print "SCORE: $Score[1] TO $Score[0]\n";
print "TIME: $Timer\n";
}
sub end_first_half
{
print "\n ***** END OF FIRST HALF *****\n\n";
print "SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n\n";
center_jump();
}
sub get_your_shot
{
$ShotType = -1;
while ($ShotType < 0 || $ShotType > 4)
{
print "YOUR SHOT (0-4): ";
chomp($ShotType = <>);
$ShotType = int($ShotType);
if ($ShotType < 0 || $ShotType > 4)
{
print "INCORRECT ANSWER. RETYPE IT. ";
}
}
}
sub center_jump
{
print "CENTER JUMP\n";
if (rand(1) <= 0.6)
{
print "$Opponent CONTROLS THE TAP.\n";
return "opp";
}
print "DARTMOUTH CONTROLS THE TAP.\n";
return "dart";
}
sub check_end_game
{
print "\n";
if ($Score[1] != $Score[0])
{
print " ***** END OF GAME *****\n";
print "FINAL SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n";
$DoPlay = 0;
}
else
{
print "\n ***** END OF SECOND HALF *****\n";
print "SCORE AT END OF REGULATION TIME:\n";
print " DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n";
print "BEGIN TWO MINUTE OVERTIME PERIOD\n";
}
}
sub two_min_left
{
print "\n *** TWO MINUTES LEFT IN THE GAME ***\n\n";
}
sub foul_shooting
{
if (rand(1) > 0.49)
{
if (rand(1) > 0.75)
{
print "BOTH SHOTS MISSED.\n";
}
else
{
print "SHOOTER MAKES ONE SHOT AND MISSES ONE.\n";
$Score[1 - $Player]++;
}
}
else
{
print "SHOOTER MAKES BOTH SHOTS.\n";
$Score[1 - $Player] += 2;
}
print_score();
}

393
07_Basketball/perl/basketball.pl Executable file
View File

@@ -0,0 +1,393 @@
#!/usr/bin/perl
# Basketball program in Perl
# While this should play the same way as the fairly faithful translation version,
# there are no GOTOs in this code. That was achieved by restructuring the program
# in the 2 *_play() subs. All of the percentages remain the same. If writing this
# from scratch, we really should have only a play() sub which uses the same code
# for both teams, but the percent edge to Darmouth has been maintained here.
# Translated by Kevin Brannen (kbrannen)
use strict;
use warnings;
# globals
my $Defense=0; # dartmouth defense value
my $Opponent; # name of opponent
my @Score = (0, 0); # scores, dart is [0], opponent is [1]
my $Player = 0; # player, 0 = dart, 1 = opp
my $Timer = 0; # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93
my $DoPlay = 1; # true if game is still being played
my $ConTeam; # controlling team, "dart" or "opp"
my $ShotType = 0; # current shot type
print "\n";
print " " x 31, "BASKETBALL";
print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY";
print "\n\n\n";
print "THIS IS DARTMOUTH COLLEGE BASKETBALL. YOU WILL BE DARTMOUTH\n";
print "CAPTAIN AND PLAYMAKER. CALL SHOTS AS FOLLOWS:\n";
print " 1. LONG (30 FT.) JUMP SHOT;\n";
print " 2. SHORT (15 FT.) JUMP SHOT;\n";
print " 3. LAY UP;\n";
print " 4. SET SHOT.\n";
print "BOTH TEAMS WILL USE THE SAME DEFENSE. CALL DEFENSE AS FOLLOWS:\n";
print " 6. PRESS;\n";
print " 6.5 MAN-TO MAN;\n";
print " 7. ZONE;\n";
print " 7.5 NONE.\n";
print "TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\n\n";
get_defense();
print "\n";
print "CHOOSE YOUR OPPONENT: ";
chomp($Opponent = <>);
$ConTeam = center_jump();
while ($DoPlay)
{
print "\n";
if ($ConTeam eq "dart")
{
get_your_shot();
dartmouth_play();
}
else
{
$ShotType = 10.0 / 4 * rand(1) + 1;
opponent_play();
}
if ($Timer >= 100)
{
check_end_game();
last if (!$DoPlay);
$Timer = 93;
$ConTeam = center_jump();
}
}
exit(0);
###############################################################
sub dartmouth_play
{
$Player = 0;
print "\n";
while (1)
{
$Timer++;
if ($Timer == 50) { end_first_half(); return; }
if ($Timer == 92) { two_min_left(); }
if ($ShotType == 0)
{
get_defense();
return; # for new ShotType
}
elsif ($ShotType == 1 || $ShotType == 2)
{
print "JUMP SHOT\n";
if (rand(1) <= 0.341 * $Defense / 8)
{
print "SHOT IS GOOD.\n";
dartmouth_score();
last;
}
if (rand(1) <= 0.682*$Defense/8)
{
print "SHOT IS OFF TARGET.\n";
if ($Defense/6*rand(1) > 0.45)
{
print "REBOUND TO $Opponent\n";
last;
}
print "DARTMOUTH CONTROLS THE REBOUND.\n";
if (rand(1) <= 0.4)
{
$ShotType = (rand(1) <= 0.5) ? 3 : 4;
next;
}
if ($Defense == 6)
{
if (rand(1) <= 0.6)
{
print "PASS STOLEN BY $Opponent, EASY LAYUP.\n";
opp_score();
next;
}
}
print "BALL PASSED BACK TO YOU.\n";
next;
}
if (rand(1) <= 0.782*$Defense/8)
{
print "SHOT IS BLOCKED. BALL CONTROLLED BY "; # no NL
if (rand(1) > 0.5)
{
print "$Opponent.\n";
last;
}
else
{
print "DARTMOUTH.\n";
next;
}
}
if (rand(1) > 0.843*$Defense/8)
{
print "CHARGING FOUL. DARTMOUTH LOSES BALL.\n";
last;
}
else
{
print "SHOOTER IS FOULED. TWO SHOTS.\n";
foul_shooting();
last;
}
}
else # elsif ($ShotType >= 3)
{
print '', ($ShotType > 3 ? "SET SHOT." : "LAY UP."), "\n";
if (7 / $Defense * rand(1) <= 0.4)
{
print "SHOT IS GOOD. TWO POINTS.\n";
dartmouth_score();
last;
}
if (7 / $Defense * rand(1) <= 0.7)
{
print "SHOT IS OFF THE RIM.\n";
if (rand(1) <= 0.667)
{
print "$Opponent CONTROLS THE REBOUND.\n";
last;
}
print "DARTMOUTH CONTROLS THE REBOUND.\n";
next if (rand(1) <= 0.4);
print "BALL PASSED BACK TO YOU.\n";
next;
}
if (7 / $Defense * rand(1) <= 0.875)
{
print "SHOOTER FOULED. TWO SHOTS.\n";
foul_shooting();
last;
}
if (7 / $Defense * rand(1) <= 0.925)
{
print "SHOT BLOCKED. $Opponent\'S BALL.\n";
last;
}
print "CHARGING FOUL. DARTMOUTH LOSES THE BALL.\n";
last;
}
}
$ConTeam = "opp";
}
sub get_defense
{
$Defense = 0;
do {
print "YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): ";
chomp($Defense = <>);
($Defense) =~ m/(\d(\.\d)?)/;
} while ($Defense < 6.0 || $Defense > 7.5)
}
sub opponent_play
{
$Player = 1;
print "\n";
while (1)
{
$Timer++;
if ($Timer == 50) { end_first_half(); return; }
if ($Timer == 92) { two_min_left(); }
if ($ShotType <= 2.0)
{
print "JUMP SHOT.\n";
if (8.0 / $Defense * rand(1) <= 0.35)
{
print "SHOT IS GOOD.\n";
opp_score();
last;
}
if (8.0 / $Defense * rand(1) <= 0.75)
{
print "SHOT IS OFF RIM.\n";
opp_missed();
return; # for possible new ShotType or team change
}
if (8.0 / $Defense * rand(1) <= 0.9)
{
print "PLAYER FOULED. TWO SHOTS.\n";
foul_shooting();
last;
}
print "OFFENSIVE FOUL. DARTMOUTH'S BALL.\n";
last;
}
else # ShotType >= 3
{
print ($ShotType > 3 ? "SET SHOT.\n" : "LAY UP.\n");
if (7.0 / $Defense * rand(1) > 0.413)
{
print "SHOT IS MISSED.\n";
{
opp_missed();
return; # for possible new ShotType or team change
}
}
else
{
print "SHOT IS GOOD.\n";
opp_score();
last;
}
}
}
$ConTeam = "dart";
}
sub opp_missed
{
if ($Defense / 6.0 * rand(1) <= 0.5)
{
print "DARTMOUTH CONTROLS THE REBOUND.\n";
$ConTeam = "dart";
}
else
{
print "$Opponent CONTROLS THE REBOUND.\n";
if ($Defense == 6)
{
if (rand(1) <= 0.75)
{
print "BALL STOLEN. EASY LAY UP FOR DARTMOUTH.\n";
dartmouth_score();
#$ConTeam = "opp";
return; # for possible new ShotType
}
}
if (rand(1) <= 0.5)
{
print "PASS BACK TO $Opponent GUARD.\n";
#$ConTeam = "opp";
return; # for possible new ShotType
}
$ShotType = (rand(1) <= 0.5) ? 3 : 4;
}
}
sub opp_score
{
$Score[0] += 2;
print_score();
}
sub dartmouth_score
{
$Score[1] += 2;
print_score();
}
sub print_score
{
print "SCORE: $Score[1] TO $Score[0]\n";
print "TIME: $Timer\n";
}
sub end_first_half
{
print "\n ***** END OF FIRST HALF *****\n\n";
print "SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n\n";
$ConTeam = center_jump();
}
sub get_your_shot
{
$ShotType = -1;
while ($ShotType < 0 || $ShotType > 4)
{
print "YOUR SHOT (0-4): ";
chomp($ShotType = <>);
$ShotType = int($ShotType);
if ($ShotType < 0 || $ShotType > 4)
{
print "INCORRECT ANSWER. RETYPE IT. ";
}
}
}
sub center_jump
{
print "CENTER JUMP\n";
if (rand(1) <= 0.6)
{
print "$Opponent CONTROLS THE TAP.\n";
return "opp";
}
print "DARTMOUTH CONTROLS THE TAP.\n";
return "dart";
}
sub check_end_game
{
print "\n";
if ($Score[1] != $Score[0])
{
print " ***** END OF GAME *****\n";
print "FINAL SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n";
$DoPlay = 0;
}
else
{
print "\n ***** END OF SECOND HALF *****\n";
print "SCORE AT END OF REGULATION TIME:\n";
print " DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n";
print "BEGIN TWO MINUTE OVERTIME PERIOD\n";
}
}
sub two_min_left
{
print "\n *** TWO MINUTES LEFT IN THE GAME ***\n\n";
}
sub foul_shooting
{
if (rand(1) > 0.49)
{
if (rand(1) > 0.75)
{
print "BOTH SHOTS MISSED.\n";
}
else
{
print "SHOOTER MAKES ONE SHOT AND MISSES ONE.\n";
$Score[1 - $Player]++;
}
}
else
{
print "SHOOTER MAKES BOTH SHOTS.\n";
$Score[1 - $Player] += 2;
}
print_score();
}