#!/usr/bin/perl # # Copyright 2011-2013 Thomas A. Alspaugh. # # This work is licensed under the # Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. # To view a copy of this license, visit # http://creativecommons.org/licenses/by-nc-sa/3.0/ # or send a letter to Creative Commons, 444 Castro Street, Suite 900, # Mountain View, California, 94041, USA. # # Attribution requirements for this file are listed at # http://www.thomasalspaugh.org/pub/attribution-by-nc-sa.html # # Timestamp 2013Feb17Su13:30 use strict; use warnings; my $cmdName = $0; sub help { print STDERR <, no period each down call is in a each up call is in a the resulting sequence is in a the name (possibly empty) is in a . -HTML includes style for each of these classes. In addition, -Hdir If -H or -HTML, each call is preceded by an arrow (down or up), even if only one direction of output calls is produced. HEREDOCUMENT ; } my $abbrCalls = ""; my $abbrNames = ""; my $fname = ""; my $fnameCount = 0; my $html = ""; my $initialized = ""; my $inputDn = ""; my $inputArrow = "↑"; my $leadStr = "lead"; my $numBells = 5; my $outputDn = ""; my $outputUp = "y"; my $outputArrow = "↑"; my @row = (); # Leads is row[0], 2nds is row[1], etc. my $rowName = ""; my $rowStr = ""; my $showArrows = ""; my $showRow0 = ""; my $showRows = "y"; my $vv = ""; my $arg = ""; for $arg (@ARGV) { if ($arg eq "--") { $fname = ""; *HIN = *STDIN; &perfile(); ++$fnameCount; } elsif ($arg =~ /^-/) { &option($arg); } else { $fname = $arg; if (open HIN, "<$fname") { &perfile(); close HIN; } else { die "($cmdName) Can't open input file $fname.\n"; } ++$fnameCount; } } if (0 == $fnameCount) { &help(); } # Deal with the option given as the first parameter. sub option { my $arg = $_[0]; if ($arg =~ /^-+help$/) { &help; exit(0); } elsif ($arg =~ /^-+a(bbr(eviated)?)?$/) { $abbrCalls = "Y"; $abbrNames = "Y"; } elsif ($arg =~ /^-+A(bbr(eviated)?Names)?$/) { $abbrNames = "Y"; } elsif ($arg =~ /^-+d(own)?$/) { $inputDn = "Y"; $inputArrow = "↓"; if ("Y" ne $outputUp) { $outputDn = "Y"; $outputUp = ""; $outputArrow = "↓"; } } elsif ($arg =~ /^-+D(own)?$/) { $outputDn = "Y"; $outputUp = ""; $outputArrow = "↓"; } elsif ($arg =~ /^-+H(TML)?$/) { $html = "Y"; } elsif ($arg =~ /^-+h(tml)?$/) { $html = "y"; } elsif ($arg =~ /^-+Hdir$/) { $showArrows = $arg; } elsif ($arg =~ /^-+n=([0-9]+)$/) { $numBells = $arg; $numBells =~ s/^-+n=([0-9]+)$/$1/; if (10 < $numBells) { die "“$arg”: Only up to 10 bells are allowed.\n"; } } elsif ($arg =~ /^-+(noRows|R)$/) { $showRows = ""; } elsif ($arg =~ /^-+u(p)?$/) { $inputDn = ""; $inputArrow = "↑"; if ("Y" != $outputDn) { $outputDn = ""; $outputUp = "Y"; $outputArrow = "↑"; } } elsif ($arg =~ /^-+U(p)?$/) { $outputDn = ""; $outputUp = "Y"; $outputArrow = "↑"; } elsif ($arg =~ /^-+U(p)?D(own)?$/) { $outputUp = "Y"; $outputDn = "Y"; $outputArrow = "↕"; } elsif ($arg =~ /^-+v$/) { $vv = "y"; } elsif ($arg =~ /^-+0$/) { $showRow0 = "y"; } else { die "Unexpected option “$arg”.\n"; } } sub perfile { # The two bells mentioned in the call my $b1 = ""; my $b2 = ""; # The bells involved in the call were in sequence $bA $bB $bC. # Down-call "$bC to $bA" is equivalent to up-call "$bB to $bC" # Down-call "$bC to lead" is equivalent to up-call "$bB to $bC" # Up-call "$bB to $bC" is equivalent to down-call "$bC to $bA" # or down-call "$bC to lead" my $bA = ""; my $bB = ""; my $bC = ""; my $callStrDn = ""; my $callStrPad = " "; my $callStrUp = ""; my $j = 0; my $n = 0; my $nPfx = ""; my $numBellsA = (10 == $numBells ? "0" : "$numBells"); @row = (); $rowName = ""; $rowStr = ""; while () { chomp; s/#.*$//; s/ +$//; if (!$_ || /^#/) { next; } if (!$initialized) { if (/^-/) { &option($_); next; } &init; } ++$n; $nPfx = ($n < 10 ? " " : ""); if ( /^([0-9])-?(L|lead)$/) { $b1 = $_; $b1 =~ s/^([0-9])-?(L|lead)$/$1/; if (!$inputDn) { die "[$nPfx$n.] “$b1 to lead”: Up-calls cannot call to lead\n"; } if ($b1 eq "0" || $b1 <= $numBells) { } else { die "[$nPfx$n.] “$b1 to lead”: $b1 is not in 1-$numBellsA\n"; } if ($vv) { print STDERR "<$nPfx$n.> $inputArrow$b1 to lead\n"; } $bA = "L"; $bB = $row[0]; $bC = $row[1]; if ($b1 == $row[1]) { $row[1] = $bB; $row[0] = $bC; } else { die "[$nPfx$n.] “$b1 to lead”: $b1 is not in 2nds:\n$rowStr\n"; } } elsif ( /^([0-9])-?([0-9])$/) { $b1 = $_; $b2 = $_; $b1 =~ s/^([0-9])-?([0-9])$/$1/; $b2 =~ s/^([0-9])-?([0-9])$/$2/; if ($b1 eq "0" || $b1 <= $numBells) { } else { die "[$nPfx$n.] “$b1 to $b2”: $b1 is not in 1-$numBellsA\n"; } if ($b2 eq "0" || $b2 <= $numBells) { } else { die "[$nPfx$n.] “$b1 to $b2”: $b2 is not in 1-$numBellsA\n"; } if ($vv) { print STDERR "<$nPfx$n.> $inputArrow$b1 to $b2\n"; } if ($inputDn) { for ($j = 0; $j < $numBells-2; ++$j) { if ($row[$j] == $b2) { if ($row[2+$j] != $b1) { die "[$nPfx$n.] ↓“$b1 to $b2”: $b1 is not two after $b2:\n$rowStr\n"; } $bA = $row[$j]; $bB = $row[$j+1]; $bC = $row[$j+2]; $row[$j+1] = $bC; $row[$j+2] = $bB; last; } } } else { # input up for ($j = 0; $j < $numBells-1; ++$j) { if ($row[$j] == $b1) { if ($row[1+$j] != $b2) { die "[$nPfx$n.] ↑“$b1 to $b2”: $b2 is not one after $b1:\n$rowStr\n"; } $bA = (0 < $j ? $row[$j-1] : "lead"); $bB = $row[$j]; $bC = $row[$j+1]; $row[$j ] = $bC; $row[$j+1] = $bB; last; } } } } else { die "[$nPfx$n.] Unrecognized call “$_”.\n"; } if ($vv) { print STDERR " $bA · $bB · $bC\n"; } $callStrPad = ("L" eq $bA && $outputDn ? "" : " "); if ("L" eq $bA) { $bA = $leadStr; } $callStrDn = ($abbrCalls ? "$bC-$bA" : "$bC to $bA"); $callStrUp = ($abbrCalls ? "$bB-$bC" : "$bB to $bC"); &makeRowStrAndName; if ($html) { my $callTd = ""; if ($outputUp && $outputDn) { $callTd = "\n" . " $callStrUp\n" . " $callStrDn\n" . " "; } elsif ($outputUp) { $callTd = "$callStrUp"; } else { $callTd = "$callStrDn"; } print < $n $callTd HEREDOCUMENT ; if ($showRows) { print <$rowStr HEREDOCUMENT ; } print <$rowName HEREDOCUMENT ; } else { my $callStr = ($outputUp ? $callStrUp . ($outputDn ? "“/”" : "") : "") . ($outputDn ? $callStrDn : ""); print "[$nPfx$n.] “$callStr”"; if ($showRows) { print "$callStrPad $rowStr"; if ($rowName ) { print " $rowName"; } } print "\n"; } } if ($html) { print < HEREDOCUMENT ; if ($html eq "Y") { print < HEREDOCUMENT ; } } } # Set $rowStr to the string version of @row. # Set $rowName to the name of the row, or "" if it has none. sub makeRowStrAndName { $rowStr = ""; my $j = ""; for ($j = 0; $j < $numBells; ++$j) { $rowStr = $rowStr . ($row[$j] == 10 ? "0" : $row[$j]); } # print "### Making row string: $rowStr\n"; if ($rowStr =~ /^123(4(5(6(7(8(9a?)?)?)?)?)?)?$/) { $rowName = ($abbrNames ? "R" : "Rounds"); } elsif ($rowStr =~ /^13(5(79?)?)?2(4(6(8a?)?)?)?$/) { $rowName = ($abbrNames ? "Q" : "Queens"); } elsif ($rowStr =~ /^(((((((a?)?9)?8)?7)?6)?5)?4)?321$/) { $rowName = ($abbrNames ? "B" : "Back Rounds"); } elsif ($rowStr =~ /^(((9?)?7)?5)?312(4(6(8a?)?)?)?$/) { $rowName = ($abbrNames ? "W" : "Whittingtons"); } elsif ($rowStr =~ /^1324?$/ || $rowStr =~ /^142536?$/ || $rowStr =~ /^15263748?$/ || $rowStr =~ /^162738495a?$/) { $rowName = ($abbrNames ? "T" : "Tittums"); } else { $rowName = ""; } } # Initialize @row to rounds for $numBells. sub rowInit { my $j = ""; for ($j = 0; $j < $numBells; ++$j) { $row[$j] = 1+$j; } } sub init { # print "### init\n"; &rowInit; &makeRowStrAndName; if ($html) { if ($html eq "Y") { print < HEREDOCUMENT ; } print < HEREDOCUMENT ; } if ($showRow0 && $showRows) { if ($html) { print < 0 $rowStr $rowName HEREDOCUMENT ; } else { print <