#!/usr/bin/perl use strict; my $HtmlFile = shift(); print "Saving HTML to $HtmlFile\n"; my $Name1 = GetPrompt("Player 1: "); my $Name2 = GetPrompt("Player 2: "); chomp($Name1,$Name2); Game($HtmlFile, $Name1,$Name2); sub Game(){ my ($HtmlFile, @Names) = @_; my $Visitor = 0; # Who is at the table (0 or 1) my $Reds = 10; # How many reds remain on the table my $Colour = 0; # What stage of the endgame are we in my $ColourOkay = 0; # Are we shooting for colour after a red my @Scores = (0,0); # Players' scores my $VisitScore = 0; # Score for this visit to the table my $VisitDescription = ""; my @GameLog; while(1){ # Display status ShowScore(\@Names, $Visitor, $Reds, $Colour, $ColourOkay,\@Scores); SaveScore($HtmlFile, \@Names, $Visitor, $Reds, $Colour, $ColourOkay,\@Scores, \@GameLog, 0); # Get keyboard input my $Ball = lc(GetPrompt(sprintf("%s's shot [1-7 or X]: ", $Names[$Visitor]))); # Missed shot if($Ball eq 'x'){ my $GameLogItem = sprintf("%s scores %d", $Names[$Visitor], $VisitScore) . ($VisitScore > 0 ? " ($VisitDescription)":"") . ($VisitScore > 0 ? sprintf(", total %d",$Scores[$Visitor]):""); push(@GameLog, $GameLogItem); if($VisitScore > 0){ Announce($Names[$Visitor], $VisitScore, 1); } $Visitor = 1 - $Visitor; $VisitScore = 0; $VisitDescription = ""; $ColourOkay = 0; } # Red ball elsif($Ball eq '1'){ if($Reds > 0){ if($ColourOkay){ Error("Invalid state (shooting for colour)\n"); } else{ $Reds--; $Scores[$Visitor]++; $VisitScore++; $VisitDescription .= "Red "; $ColourOkay = 1; Announce($Names[$Visitor], 1); if($Reds == 0){ $Colour = 2; } } } else{ Error("Invalid state (no reds remain)\n"); } } # Coloured ball elsif($Ball > 1 && $Ball <= 7){ # Endgame colours if($Reds == 0 && !$ColourOkay){ if($Ball == $Colour){ $Scores[$Visitor] += $Ball; $VisitScore += $Ball; $VisitDescription .= GetColour($Ball) . " "; Announce($Names[$Visitor], $Ball, 0); if($Colour == 7){ print "End of game (pot black)\n"; my $GameLogItem = sprintf("%s scores %d, ending this game (%s), total %d", $Names[$Visitor], $VisitScore, $VisitDescription, $Scores[$Visitor]); push(@GameLog, $GameLogItem); SaveScore($HtmlFile, \@Names, $Visitor, $Reds, $Colour, $ColourOkay,\@Scores, \@GameLog, 1); exit; } else{ $Colour++; } } else{ Error("Invalid state (shooting for %s)\n",GetColour($Colour)); } } # Startgame colours else{ if($ColourOkay){ $Scores[$Visitor] += $Ball; $VisitScore += $Ball; $VisitDescription .= GetColour($Ball) . " "; Announce($Names[$Visitor], $Ball, 0); $ColourOkay = 0; } else{ Error("Invalid state (not shooting for colour)\n"); } } } elsif($Ball eq '?'){ Helpfile(); } elsif($Ball eq 'q'){ exit; } else{ Error("Invalid command (q for quit, ? for help)\n"); } } } sub Announce(){ my ($Name, $Score, $IsChangeover) = @_; if($IsChangeover){ print "> Loud voice: $Name scores $Score\n"; } else{ print "> Soft voice: $Name, $Score\n"; } } sub SaveScore(){ my ($HtmlFile,$RefNames,$Visitor,$Reds,$Colour,$ColourOkay,$RefScores, $RefGameLog, $Finished) = @_; my @Names = @$RefNames; my @Scores = @$RefScores; my @GameLog = @$RefGameLog; my $Text = ""; my $Remaining = GetRemaining($Reds, $Colour); my $PlayFor = ""; if($ColourOkay){ $PlayFor = "a colour"; } else{ if($Reds > 0){ $PlayFor = "a red"; } else{ $PlayFor = "the " . lc(GetColour($Colour)); } } if($Finished){ # Finished, draw if($Scores[0] == $Scores[1]){ $Text .= sprintf("

Game is finished. %s draws with %s, at %d-all

\n", $Names[0], $Names[1], $Scores[0]); } # Finished, not a draw else{ my $First = ($Scores[0] > $Scores[1]) ? 0 : 1; my $Second = 1 - $First; # Finished, in a single break $Text .= sprintf("

Game is finished. %s wins against %s with a score of %d to %d

\n", $Names[$First], $Names[$Second], $Scores[$First], $Scores[$Second]); } } # Game still in progress else{ # Display players and their scores foreach my $ii(0..1){ if($Visitor == $ii){ $Text .= sprintf("

%s is at the table, playing for %s, with a score of %d

\n", $Names[$ii], $PlayFor, $Scores[$ii]); } else{ $Text .= sprintf("

%s has a score of %d

\n", $Names[$ii], $Scores[$ii]); } } $Text .= "
\n"; # Display stats $Text .= "

\n"; if($Reds > 0 || $ColourOkay){ $Text .= sprintf("%d %s on the table, ", $Reds, $Reds > 1 ? "reds":"red"); } else{ $Text .= sprintf("Endgame, %s is the next colour. ", lc(GetColour($Colour))); } $Text .= sprintf("%d points remaining\n", $Remaining); $Text .= "

\n"; } # Display transcript of the entire game if(length(@GameLog) > 0){ $Text .= "Transcript:\n
    \n"; my $Count = 1; foreach my $Item (@GameLog){ $Text .= "
  1. $Item
  2. \n"; } $Text .= "
\n"; } # Put together an HTML document my $Title = sprintf("Results for %s vs %s", $Names[0], $Names[1]); my $Head = "\n$Title\n\n"; my $Body = "

$Title

\n$Text\n\n"; my $Html = "\n$Head\n$Body\n\n"; # Save the HTML document open(my $fp, ">", $HtmlFile) || return(print("File error: $!\n")); print $fp $Html; close $fp; } sub ShowScore(){ my ($RefNames,$Visitor,$Reds,$Colour,$ColourOkay,$RefScores) = @_; my @Names = @$RefNames; my @Scores = @$RefScores; # Calculate number of points remaining on the table my $Remaining = GetRemaining($Reds, $Colour); my $Difference = $Scores[0] - $Scores[1]; if($Difference < 0){ $Difference *= -1; } # Format each person's score, and highlight the visitor my @Displays; foreach my $ii(0..1){ $Displays[$ii] = sprintf("%s = %d", $Names[$ii], $Scores[$ii]); if($Visitor == $ii){ $Displays[$ii] = "[" . $Displays[$ii] . "]"; } } # Display those scores printf("\n%s, %s, %d ahead, %d remaining\n", $Displays[0], $Displays[1], $Difference,$Remaining); # Display game status if($ColourOkay){ printf("Playing for colour, %d reds remaining\n", $Reds); } else{ if($Reds > 0){ printf("Playing for red. %d reds remaining\n",$Reds); } else{ printf("Playing for %s\n", GetColour($Colour)); } } } sub GetColour(){ my @Colours = split(/,/,"None,Red,Yellow,Green,Brown,Blue,Pink,Black"); return($Colours[shift()]); } sub GetRemaining(){ my $Remaining = 0; for(my $ii = shift(); $ii > 0; $ii--){ $Remaining += (1 + 7); } for(my $ii = shift(); $ii <= 7; $ii++){ $Remaining += $ii; } return($Remaining); } sub GetPrompt(){ print shift(); my $Answer = ; chomp $Answer; return($Answer); } sub Helpfile(){ print "TODO: helpfile\n"; } sub Error(){ printf("%s\n%s\n%s\n", "#" x 60, "## " . shift(), "#" x 60); }