added 56-life2 for perl

added a perl version for the game;
fixed a bug in the basic code;
updated the game's README;
updated perl's README.
This commit is contained in:
kbrannen
2023-05-19 02:11:02 -05:00
parent 3ebb958b3f
commit 46f98ca01d
4 changed files with 249 additions and 2 deletions

View File

@@ -48,3 +48,17 @@ http://www.vintage-basic.net/games.html
#### Porting Notes
(please note any difficulties or challenges in porting here)
Note: The original program has a bug. The instructions say that if both players
enter the same cell that the cell is set to 0 or empty. However, the original
Basic program tells the player "ILLEGAL COORDINATES" and makes another cell be entered,
giving a slightly unfair advantage to the 2nd player.
The Perl verson of the program fixes the bug and follows the instructions.
Note: The original code had "GOTO 800" but label 800 didn't exist; it should have gone to label 999.
The Basic program has been fixed.
Note: The Basic program is written to assume it's being played on a Teletype, i.e. output is printed
on paper. To play on a terminal the input must not be echoed, which can be a challenge to do portably
and without tying the solution to a specific OS. Some versions may tell you how to do this, others might not.

View File

@@ -60,8 +60,8 @@
571 IF M3=0 THEN B=1: GOTO 575
572 IF M2=0 THEN B=2: GOTO 575
573 GOTO 580
574 PRINT: PRINT "A DRAW":GOTO 800
575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 800
574 PRINT: PRINT "A DRAW":GOTO 999
575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 999
580 FOR B=1 TO 2: PRINT: PRINT: PRINT "PLAYER";B;: GOSUB 700
581 IF B=99 THEN 560
582 NEXT B

View File

@@ -1,3 +1,21 @@
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
Conversion to [Perl](https://www.perl.org/)
Note: The original program has a bug (see the README in the above dir). This Perl version fixes it.
Note: For input, the X value is to the right while the Y value is down.
Therefore, the top right cell is "5,1", not "1,5".
The original program was made to be played on a Teletype, i.e. a printer on paper.
That allowed the program to "black out" the input line to hide a user's input from his/her
opponent, assuming the opponent was at least looking away. To do the equivalent on a
terminal would require a Perl module that isn't installed by default (i.e. it is not
part of CORE and would also require a C compiler to install), nor do I want to issue a
shell command to "stty" to hide the input because that would restrict the game to Linux/Unix.
This means it would have to be played on the honor system.
However, if you want to try it, install the module "Term::ReadKey" ("sudo cpan -i Term::ReadKey"
if on Linux/Unix and you have root access). If the code finds that module, it will automatically
use it and hide the input ... and restore echoing input again when the games ends. If the module
is not found, input will be visible.

View File

@@ -0,0 +1,215 @@
#!/usr/bin/perl
# Life_For_Two program in Perl
# Required extensive restructuring to remove all of the GOTO's.
# Translated by Kevin Brannen (kbrannen)
use strict;
use warnings;
# try to load module to hide input, set RKey to true if found
my $Rkey = eval { require Term::ReadKey } // 0;
END { Term::ReadKey::ReadMode('normal') if ($Rkey); }
# globals
my @Board; # 2D board
my @X; # ?
my @Y; # ?
my $Player; # 1 or 2
my $M2 = 0; # ?
my $M3 = 0; # ?
# add 0 on front to make data 1 based
my @K = (0,3,102,103,120,130,121,112,111,12,21,30,1020,1030,1011,1021,1003,1002,1012);
my @A = (0,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1);
print "\n";
print " " x 33, "LIFE2\n";
print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n";
print " " x 10, "U.B. LIFE GAME\n";
for my $j (1 .. 5) { for my $k (1 .. 5) { $Board[$j][$k] = 0; } }
for (1 .. 2)
{
$Player = $_; # if we make $Player the loop var, the global isn't set
my $p1 = ($Player == 2) ? 30 : 3;
print "\nPLAYER $Player - 3 LIVE PIECES.\n";
for (1 .. 3)
{
get_input();
$Board[$X[$Player]][$Y[$Player]] = $p1 if ($Player != 99);
}
}
print_board(); # print board after initial input
while (1)
{
print "\n";
calc_board(); # calc new positions
print_board(); # print current board after calc
if ($M2 == 0 && $M3 == 0)
{
print "\nA DRAW\n";
last;
}
if ($M3 == 0)
{
win(1);
last;
}
if ($M2 == 0)
{
win(2);
last;
}
for (1 .. 2)
{
$Player = $_; # if we make $Player the loop var, the global isn't set
print "\n\nPLAYER $Player ";
get_input();
last if ($Player == 99);
}
next if ($Player == 99);
$Board[$X[1]][$Y[1]] = 100;
$Board[$X[2]][$Y[2]] = 1000;
}
exit(0);
###########################################################
sub win
{
my $p = shift;
print "\nPLAYER $p IS THE WINNER\n";
}
sub calc_board
{
for my $j (1 .. 5)
{
for my $k (1 .. 5)
{
if ($Board[$j][$k] > 99)
{
$Player = $Board[$j][$k] > 999 ? 10 : 1;
for (my $c = 1 ; $c <= 15 ; $c += 2)
{
$Board[$j+$A[$c]][$k+$A[$c+1]] = ($Board[$j+$A[$c]][$k+$A[$c+1]] // 0) + $Player;
}
}
}
}
}
sub print_board
{
$M2 = 0;
$M3 = 0;
for my $j (0 .. 6)
{
print "\n";
for my $k (0 .. 6)
{
if ($j != 0 && $j != 6)
{
if ($k != 0 && $k != 6)
{
print_row($j, $k);
next;
}
if ($j == 6)
{
print "0\n";
return;
}
print " $j ";
}
else
{
if ($k == 6)
{
print " 0 ";
last;
}
print " $k ";
}
}
}
}
sub print_row
{
my ($j, $k) = @_;
if ($Board[$j][$k] >= 3)
{
my $c;
for $c (1 .. 18)
{
if ($Board[$j][$k] == $K[$c])
{
if ($c <= 9)
{
$Board[$j][$k] = 100;
$M2++;
print " * ";
}
else
{
$Board[$j][$k] = 1000;
$M3++;
print " # ";
}
return;
}
}
}
$Board[$j][$k] = 0;
print " ";
}
sub get_input
{
while (1)
{
print "X,Y\n";
my $ans;
if ($Rkey)
{
# code to hide input
Term::ReadKey::ReadMode('noecho');
$ans = Term::ReadKey::ReadLine(0);
Term::ReadKey::ReadMode('restore');
print "\n"; # do this since the one entered was hidden
}
else
{
# normal, input visible
chomp($ans = <>);
}
($Y[$Player], $X[$Player]) = split(/[,\s]+/, $ans, 2);
if ($X[$Player] > 5 || $X[$Player] < 1 || $Y[$Player] > 5 || $Y[$Player] < 1)
{
print "ILLEGAL COORDS. RETYPE\n";
next;
}
# this tells you the cell was already taken not zero it out, bug!
#if ($Board[$X[$Player]][$Y[$Player]] != 0)
#{
# print "ILLEGAL COORDS. RETYPE\n";
# next;
#}
last;
}
return if ($Player == 1 || $X[1] != $X[2] || $Y[1] != $Y[2]);
print "SAME COORD. SET TO 0\n";
$Board[$X[$Player]+1][$Y[$Player]+1] = 0;
$Player = 99;
}