#!/usr/bin/perl
use strict;
use warnings;
###################################################USER VARIABLES
#define number of people, number of prizes, number of draws (> 5)
my $people = 10;
my $prizes = 8;
my $draws = 22*2;
#define total set of BINGO numbers
#range of numbers
my $range = 75;
####################################################INTERNAL/DEVELOPMENT VARIABLES
my $bin = int $range/5;
my @bins = ($bin, 2*$bin, 3*$bin, 4*$bin);
#my @seq = @fudgedDrawSeq;
my (@callseq, @noncallseq); #auxillary lists to build
my @winstring;
####################################################MAIN EXECUTION 1
###########-this part used to define metadata; cards outputed from metadata
###########-this metadata needed so Matt can have the draw sequence now.
#my %ball; #hash containing $range BINGO balls THIS SHOULDN'T BE HERE
#my @drawSeq; #for &defDrawSeq, draw sequence
#&defDrawSeq; #define @drawSwq
#my @seq = @drawSeq; #for modularity to &mkWinstring
#print "DEBUG: @seq\n";
#print "CALL SEQUENCE:";
#for (0..($draws-1)){push( @callseq, $seq[$_] ); print "$seq[$_], ";}
#print "\nNONCALL SEQUENCE:";
#for ($draws..($range-1)){push( @noncallseq, $seq[$_] ); print "$seq[$_], ";}
#&mkWinstring;###############################################################
#unless (&chkWinstring){die "\nplease rerun, internal randomization error"}
#&mkCards;
####################################################FUNCTIONS 1
sub defDrawSeq (){
#define draw sequences (string of $draw numbers, randomized with hashtable lookup)
{
for (1..$range){
if ( $_ <= $bins[0] ){$ball{$_}="B-$_"}
elsif ( $_ <= $bins[1] ){$ball{$_}="I-$_"}
elsif ( $_ <= $bins[2] ){$ball{$_}="N-$_"}
elsif ( $_ <= $bins[3] ){$ball{$_}="G-$_"}
else{$ball{$_}="O-$_"};
}
}
for (keys %ball){
push (@drawSeq, $ball{$_}); #print "\'$ball{$_}\', ";
};
}
sub chkWinstring () {
for (@winstring){
my @temp = split;
my ($sum,$err);
for (@temp){$sum++;}
if ($sum != 5){return 1}else{return 0}
}
}
sub mkWinstring (){
my (@b, @i, @n, @g, @o);
for (0..($draws-1)){
local $_ = $seq[$_];
# print "DEBUG $_\n";
if (m,B,){push(@b,$_);next;}
elsif(m,I,){push(@i,$_);next;}
elsif(m,N,){push(@n,$_);next;}
elsif(m,G,){push(@g,$_);next;}
elsif(m,O,){push(@o,$_);next;}
}
print "\nSUBLISTS FOR CARD MAKING:\n";
print "***\n B: @b \nI: @i\nN: @n\nG: @g\nO: @o\n***\n";
for my $j (0..($prizes-1))
{
my $winstring = $b[$j].' '.$i[$j].' '.$n[$j].' '.$g[$j].' '.$o[$j]."\n";
my @temp = split(/\s+/,$winstring);
my $temp; for (@temp){$temp++;} #print "DEBUG $m\n";}
if ($temp == 5){
push (@winstring, $winstring);
}else{
print "ERROR $winstring";
}
} print "WINSTRINGS:\n***\n@winstring***\n";
}
sub mkCards{#needs global @winstring
my( @wincard, @losecard);
#print winning cards;
print "WINNING CARDS:\n";
for my $k (1..$prizes)
{
my $l = "$winstring[$k-1]";
print "LINESTRING 0: $l";
for my $line (1..4)
{
my $linestring;
my $pos = &getPos();
my $temp = &getDrawBall;
print "$temp ";
# if( $pos == 1 ){ $linestring = ";}
# elsif( $pos == 2 ){ $linestring = "$b[$j] $i[$j] $n[$j] $g[$j] $o[$j]\n";}
# elsif( $pos == 3 ){ $linestring = "$b[$j] $i[$j] $n[$j] $g[$j] $o[$j]\n";}
# elsif( $pos == 4 ){ $linestring = "$b[$j] $i[$j] $n[$j] $g[$j] $o[$j]\n";}
# print "\nLINESTRING $line: $linestring\n";
}
}
}
sub getRand(){
while (1){
my $temp = int(1111*rand()/11);
unless ($temp = 0) {return $temp; exit}
}
}
sub getPos(){
while (1){
my $temp = int((1111*rand()/111)%5)+1;
unless ($temp > 5) {return $temp; exit}
}
}
####
DEBUG: N-42 N-34 O-67 G-59 B-9 O-71 O-75 O-72 O-73 I-22 B-15 O-63 O-70 I-19 B-3 N-32 G-48 N-33 O-74 N-31 B-10 N-37 B-4 N-36 B-7 I-26 G-47 G-51 G-57 I-30 G-52 I-20 O-62 G-58 N-38 I-16 I-24 I-25 G-49 B-8 N-44 B-13 I-28 G-50 O-61 O-64 N-39 G-54 I-23 B-14 I-17 N-45 N-35 B-6 B-5 B-12 G-53 O-65 I-27 O-66 N-41 G-55 O-68 G-56 G-46 N-43 B-11 I-29 N-40 O-69 B-2 G-60 I-21 I-18 B-1
CALL SEQUENCE:N-42, N-34, O-67, G-59, B-9, O-71, O-75, O-72, O-73, I-22, B-15, O-63, O-70, I-19, B-3, N-32, G-48, N-33, O-74, N-31, B-10, N-37, B-4, N-36, B-7, I-26, G-47, G-51, G-57, I-30, G-52, I-20, O-62, G-58, N-38, I-16, I-24, I-25, G-49, B-8, N-44, B-13, I-28, G-50,
NONCALL SEQUENCE:O-61, O-64, N-39, G-54, I-23, B-14, I-17, N-45, N-35, B-6, B-5, B-12, G-53, O-65, I-27, O-66, N-41, G-55, O-68, G-56, G-46, N-43, B-11, I-29, N-40, O-69, B-2, G-60, I-21, I-18, B-1,
SUBLISTS FOR CARD MAKING:
***
B: B-9 B-15 B-3 B-10 B-4 B-7 B-8 B-13
I: I-22 I-19 I-26 I-30 I-20 I-16 I-24 I-25 I-28
N: N-42 N-34 N-32 N-33 N-31 N-37 N-36 N-38 N-44
G: G-59 G-48 G-47 G-51 G-57 G-52 G-58 G-49 G-50
O: O-67 O-71 O-75 O-72 O-73 O-63 O-70 O-74 O-62
***
WINSTRINGS:
***
B-9 I-22 N-42 G-59 O-67
B-15 I-19 N-34 G-48 O-71
B-3 I-26 N-32 G-47 O-75
B-10 I-30 N-33 G-51 O-72
B-4 I-20 N-31 G-57 O-73
B-7 I-16 N-37 G-52 O-63
B-8 I-24 N-36 G-58 O-70
B-13 I-25 N-38 G-49 O-74
***
####
#!/usr/bin/perl
#rigged BINGO name, part 2 (known sequence of call numbers, random distribution of cards)
#all winning cards are double bingos; one unspoiled point at diagonal
#all losing cards hit 20 numbers; spoiled (noncalled) numbers at either (randomly chosen) diagonal ensure nonwinnner, but exciting
use strict;
use warnings;
my $losers = 120;
my $prizes = 8;
#my $losers = 6;
#my $prizes = 0;
#this script corrupts original @callseq
my( @callseq, @winstring, @noncallseq); #auxillary lists to build ###NO LONGER NEED WINSTRING 3.0
my( @wincard, @losecard); #lists of strings, strings are info for cards
my( %serialNumber );
####################################################MAIN EXECUTION 2
&doInit;
&mkCards;
my @allcards = (@losecard,@wincard);
print '\documentclass[portrait]{seminar}
\slidesmag{6}
\slideframe{none}
\usepackage{graphicx}
\usepackage{times}
\begin{document}
\begin{center}
';
my $count;
for (@allcards){
if (m,([01]{10})\n((?:(?:\w\-\d+[\s\n]){5}){5}),)
{
my $code = $1;
my $card = $2;
$card =~ s,((?:\w\-\d+\s){5}),$1\n,g;
$card =~ s,\w\-(\d+),$1,g;
$card =~ s, , \& ,g;
$card =~ s,\&\s*?\n,\\\\\n\\hline\n,g;
print '\begin{tabular}[]{| c | c | c | c | c |}';
print "\n";
print '\multicolumn{5}{c}{{\large B}IOCHEMISTRY {\large R}ETREAT {\large 2005}} \\\\';
print "\n";
print '{\huge \bf B} & {\huge \bf I } & {\huge \bf N } & {\huge \bf G } & {\huge \bf O! } \\\\[-1.5pt] \hline';
print "\n";
print "$card";
print '\multicolumn{5}{c}{{\tiny '."$code"."}}\n\n";
print '\end{tabular}'."\n%%%%%\n";
}}
print '\end{center}
\end{document}';
####################################################FUNCTIONS
sub mkCards{
#needs global @winstring
#print losing cards;
##################################################################################
for my $k (1..$losers)
{
my $linestring;
my $count = 0;
my %seen;
local *getNewDrawBall = sub { #workaround for scoping inner subroutine with typeglob - ugly Perlism
my $type = shift;
my $temp2;
while (1){
$temp2 = &getDrawBall($type);
if (exists $seen{$temp2})
{
next;
}else{ $seen{$temp2}++;return $temp2;} #print "DEBUGdraw: $temp\n";
}
};
local *getNewNonDrawBall = sub { #workaround for scoping inner subroutine with typeglob - ugly Perlism
my $type = shift;
my $temp2;
while (1){
$temp2 = &getNonDrawBall($type);
if (exists $seen{$temp2})
{
next;
}else{ $seen{$temp2}++;return $temp2;} #print "DEBUG_no_draw: $temp\n";
}
};
#SPOIL CARD HERE
my @spoil = &getSpoilScheme(); ### @SPOIL DECLARED HERE ###
my $scheme;
if ($spoil[0] == 0){$scheme= '01'}else{$scheme = '10'};
############serial number
local *coinFlip = sub {
my $z = &getRand;
my $coin = int($z)% 2;
return $coin;
};
local *buildSN = sub {
my @sn;
for (1..4){
local $_ = &coinFlip;
push( @sn, $_);
};
push( @sn, "$scheme");
for (1..4){
local $_ = &coinFlip;
push( @sn, $_);
};
my $temp = "@sn";
$temp =~ s,\s+,,g;
#
$temp;};
my $sn;my $thing =1;
while ($thing == 1){
$sn = &buildSN;
unless (exists $serialNumber{$sn}){
$thing=0}};
my $spoilflag = 'nospoil';
#actually write card
for my $num (1..25)
{
my( $mod, $temp);
$mod = $num % 5;
if (($num) == ($spoil[0] + 1)) ##SET SPOILFLAG
{
shift @spoil unless (@spoil == 1);
$spoilflag = 'spoil';
}else{
$spoilflag = 'nospoil';
};
# print "DEBUG.spoil: k $k num $num flag $spoilflag spoil @spoil \n";
if ($spoilflag eq 'nospoil') ##REACT TO SPOILFLAG
{
if( $mod == 1){$temp = &getNewDrawBall('B');$seen{$temp}++;}
elsif( $mod == 2){$temp = &getNewDrawBall('I');$seen{$temp}++;}
elsif( $mod == 3){$temp = &getNewDrawBall('N');$seen{$temp}++;}
elsif( $mod == 4){$temp = &getNewDrawBall('G');$seen{$temp}++;}
elsif( $mod == 0){$temp = &getNewDrawBall('O');$seen{$temp}++;};
}elsif($spoilflag eq 'spoil')
{
if( $mod == 1){$temp = &getNewNonDrawBall('B');$seen{$temp}++;}
elsif( $mod == 2){$temp = &getNewNonDrawBall('I');$seen{$temp}++;}
elsif( $mod == 3){$temp = &getNewNonDrawBall('N');$seen{$temp}++;}
elsif( $mod == 4){$temp = &getNewNonDrawBall('G');$seen{$temp}++;}
elsif( $mod == 0){$temp = &getNewNonDrawBall('O');$seen{$temp}++;};
}else{die "THIS SHOULDN'T HAPPEN\n";};
$linestring .= "$temp ";
$count++;
# print "DEBUG: k $k n $num m $mod t $temp\n";
}
push( @losecard , ($sn."\n".$linestring));
}
#print win cards
##################################################################################
for my $k2 (1..$prizes)
{
my $linestring;
my $count = 0;
my %seen;
local *getNewDrawBall = sub { #workaround for scoping inner subroutine with typeglob - ugly Perlism
my $type = shift;
my $temp2;
while (1){
$temp2 = &getDrawBall($type);
if (exists $seen{$temp2})
{
next;
}else{ $seen{$temp2}++;return $temp2;} #print "DEBUGdraw: $temp\n";
}
};
local *getNewNonDrawBall = sub { #workaround for scoping inner subroutine with typeglob - ugly Perlism
my $type = shift;
my $temp2;
while (1){
$temp2 = &getNonDrawBall($type);
if (exists $seen{$temp2})
{
next;
}else{ $seen{$temp2}++;return $temp2;} #print "DEBUG_no_draw: $temp\n";
}
};
#SPOIL CARD HERE
my @spoil = &getSpoilScheme();
my $spoilflag = 'nospoil';
#actually write card
#define modified spoil and winstring
my $winline;
my %winNums;
my $tempWL = 1;
while ($tempWL == 1) {$winline = &getRand; if ($winline < 5){$tempWL = 0};} #perhaps cleaner way to deal with loops; uses variables though
my $winNumStart = 5 * $winline - 4;
for ($winNumStart .. ($winNumStart+4)){$winNums{$_}++};
local *coinFlip = sub {
my $z = &getRand;
my $coin = int($z)% 2;
return $coin;
};
############serial number
my $scheme = '11';
local *buildSN = sub {
while (1){
my @sn;
for (1..4){
local $_ = &coinFlip;
push( @sn, $_);
};
push( @sn, "$scheme");
for (1..4){
local $_ = &coinFlip;
push( @sn, $_);
};
my $temp = "@sn";
$temp =~ s,\s+,,g;
# unless (exists $serialNumber{$temp}){
return $temp;
}} ;
my $sn;my $thing =1;
while ($thing == 1){
$sn = &buildSN;
unless (exists $serialNumber{$sn}){
$thing=0}};
for my $num (1..25)
{
my( $mod, $temp);
$mod = $num % 5;
if (($num) == ($spoil[0] + 1)) ##SET SPOILFLAG
{
shift @spoil unless (@spoil == 1);
$spoilflag = 'spoil'; #print "intend to spoil $num\n";
}else{
$spoilflag = 'nospoil';
};
if(exists $winNums{$num})
{
$spoilflag = 'nospoil'; #print "spoiling of $num rescued here\n";
}
# print "DEBUG.spoil: k $k num $num flag $spoilflag spoil @spoil \n";
if ($spoilflag eq 'nospoil') ##REACT TO SPOILFLAG
{
if( $mod == 1){$temp = &getNewDrawBall('B');$seen{$temp}++;}
elsif( $mod == 2){$temp = &getNewDrawBall('I');$seen{$temp}++;}
elsif( $mod == 3){$temp = &getNewDrawBall('N');$seen{$temp}++;}
elsif( $mod == 4){$temp = &getNewDrawBall('G');$seen{$temp}++;}
elsif( $mod == 0){$temp = &getNewDrawBall('O');$seen{$temp}++;};
}elsif($spoilflag eq 'spoil')
{
if( $mod == 1){$temp = &getNewNonDrawBall('B');$seen{$temp}++;}
elsif( $mod == 2){$temp = &getNewNonDrawBall('I');$seen{$temp}++;}
elsif( $mod == 3){$temp = &getNewNonDrawBall('N');$seen{$temp}++;}
elsif( $mod == 4){$temp = &getNewNonDrawBall('G');$seen{$temp}++;}
elsif( $mod == 0){$temp = &getNewNonDrawBall('O');$seen{$temp}++;};
}else{die "THIS SHOULDN'T HAPPEN\n";};
$linestring .= "$temp ";
$count++;
# print "DEBUG: k $k n $num m $mod t $temp\n";
}
push( @wincard , ($sn."\n".$linestring));
}
}
sub getSpoilScheme{
my @spoil;
my @spoil1 = (0,6,12,18,24);
my @spoil2 = (4,8,12,16,20);
#select spoil scheme (coin flip)
my $z = &getRand;
my $coin = int($z)% 2;
if ($coin==0){@spoil = @spoil1}else{@spoil = @spoil2};
# print "DEBUGspoil\:\: z $z coin $coin spoil @spoil\n";
return @spoil;
}
sub getRand{
my $temp;
while (1){
$temp = int(1111*rand()/11);
unless ($temp == 0) {return $temp}}};
sub getDrawBall{
my $type = shift;
while (1){
my $temp = pop @callseq;
unshift( @callseq, $temp );
if ($temp =~ /$type/){return $temp; print "DEBUG getDrawBall: $temp\n";}}}
sub getNonDrawBall{
my $type = shift;
while (1){
my $temp = pop @noncallseq;
unshift( @noncallseq, $temp ); #print "sNDB\:\: TEMP $temp TYPE $type\n";
if ($temp =~ /$type/){return $temp; print "DEBUG getnonDrawBall: $temp\n";}}}
###########-this part used to load predefined metadata; cards outputed from metadata
###########-this metadata needed so Matt can have the draw sequence now.
sub doInit () #with lispy whitespace!
{
open (IN, "metadata2.dat");
my $tempState = 'start';
while( ){
if ( m{\ACALL SEQUENCE:([^\n]+),} ){
$tempState = 'callseq';
my $temp = $1; #print "$temp\n";
$temp =~ s/,//g;
@callseq = split(/\s+/,$temp);
}
# print "DEBUGY3: here\n";
# for (@callseq){print "callseq:: $_\n";}
if ( m!
\A NONCALL\sSEQUENCE: ([^\n]+),
!x){
# print "DEBUGY2: here\n";
$tempState = 'noncallseq';
my $temp = $1; #print "$temp\n";
$temp =~ s/,//g;
@noncallseq = split(/\s+/,$temp);
# for (@noncallseq){print "DEBUGY1: noncallseq\:\: $_\n";}
if ( m{WINSTRINGS} ){
$tempState = 'winstring';
next;}
if ($tempState eq 'winstring'){
next if (m,\*{3},);
if ( m,\s?(B-\d.+?)\n, ){
push( @winstring,$_ );}}}}}
#{#test suite
#print "LOSECARDS:\n";
#{my $i;for(@losecard){$i++; s,((?:\w\-\d+\s){5}),$1\n,g;}}
#{my $i;for(@wincard){$i++; s,((?:\w\-\d+\s){5}),$1\n,g;}}
#my $test = &chkCards(\@wincard);
#$test =~ s,((?:[\w\!]+\s){5}),$1\n,g;
#$test =~ s,((?:[^\n]+\n){5}),$1\n,g;
#$test =~ s,((?:!DAUB!\s?){5}),$1 OOOO,g;
#print "$test";
#$test = &chkCards(\@losecard);
#$test =~ s,((?:[\w\!]+\s){5}),$1\n,g;
#$test =~ s,((?:[^\n]+\n){5}),$1\n,g;
#$test =~ s,((?:!DAUB!\s?){5}),$1 OOOO,g;
#print "$test";
#$test = &testSuite;
#my $ref = $test;
#my %testSeen;
#$test =~ s,([01]{10}),$1(?{$testSeen{$1}++}),g;
#for ( sort{ $a <=> $b } keys %testSeen )
#for ( keys %testSeen )
#{print;print "\n";};
#}
#my @allcards = push( @wincard, @losecard );
#{my $i;for(@allcards){$i++; s,((?:\w\-\d+\s){5}),$1\n\n,g;print "$i\n";print;}}
#sub chkCards{
# my @cards = shift;
# my $count;
# my $out;
# my( %call, %nocall);
# for (@callseq){$call{$_}++};
# for (@noncallseq){$nocall{$_}++};
# local *chkCard = sub {
# my $card = shift;
# my @seq = split(/\s+/,$card);
# for (@seq)
# {
# if (m,[01]{10},){print "$&\n";next;}
# if(exists $call{$_}){
# $out .= "!DAUB! ";
# }elsif(exists $nocall{$_}){
# $out .= "NODAUB ";
# }else{
# die "this shouldn't happen";
# }
# }
# };
# for (@wincard){
# &chkCard($_)
# };
# return $out;
#}