Thread Bingokarten erstellen
(11 answers)
Opened by frankes at 2010-09-27 22:19
Erstmal nochmals ein großes Dankeschön an Renee, payx und clms.
Eigentlich wäre eine Runde Bier an euch fällig, aber leider lässt Otherland noch auf sich warten. Inzwischen habe ich eure Vorschläge aufgegriffen und mit Renees vorgeschlagenen Modul Math::Combinatories verbunden. Um eine gleichmäßige Verteilung der Begriffe zu erhalten, werden die einzelnen Karten nicht mehr zufällig mit Begriffen gefüllt, sondern neu zu erstellende Karten mit den am seltensten verwendeten Begriffen aufgefüllt. Zum überprüfen der Einmaligkeit kommt dann Math::Combinatories zum Einsatz, welches mir eine Liste aller möglichen Kombinationen zur Verfügung stellt und durch Löschen der verwendeten Kombinationen als Referenz dient. Sollte eine Karte mit den am seltensten genutzten Begriffen bereits in Verwendung sein, so wird durch entfernen des jeweils häufigsten (seltenen) Begriffs zunächst nach einer ähnlichen Begriffskombination gesucht. Nachfolgend der momentane Stand meines Codes. Kritik und Vorschläge sind natürlich willkommen. Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 #!/usr/bin/perl use strict; use warnings; use Math::Combinatorics; my $cardNo = 20; # No. of cards to create my $cardFields = 6; # fields at one card my @terms = qw( term1 term2 term3 term4 term5 term6 term7 term8 term9 term10 ); # check if order possible if ( $cardFields > scalar @terms ) { die 'There are not enough terms (' ,scalar @terms ,") for $cardFields fields per card\n" ,$!; } # Edit 1: folgende Fehlerabfrage wurde nachträglich eingefügt elsif ( $cardNo*$cardFields < scalar @terms ) { die "$cardNo cards with $cardFields fields haven`t " ,'enought place for ',scalar @terms,' terms.',$!; } my @termNo = (0..scalar @terms-1); # just a help for keynames # Terms counter for a uniform distribution # %countTerms wird als Referenz genutzt, # um die Häufigkeit der verwendeten Begriffe # zu zählen my %countTerms = (); @countTerms{@termNo} = split ',',('0,' x scalar @termNo); # get all combinations as referenz my %allCombi = (); my $combinat = Math::Combinatorics->new( 'count' => $cardFields, 'data' => [@termNo], ); while(my @combo = $combinat->next_combination){ my $combo = join '-',sort{$a <=> $b}@combo; $allCombi{$combo} = 0; } # check if order possible my $possibleCards = scalar( keys %allCombi ); if ( $possibleCards < $cardNo) { die 'There are only ' ,$possibleCards ," combinations possible.\n" ,'but you ordered ' ,$cardNo, " cards.\n" ,$!; } # just a info print "There are $possibleCards combinations possible.\n\n"; # if all possible combinations in use # eine Abkürzung, wenn wirklich alle Kombinationen benötigt werden if ( $cardNo == $possibleCards ) { giveOut(\%allCombi); exit 0; } # Eine erste Karte zu erstellen wäre wahrscheinlich nicht nötig # kam mir aber als gute Idee vor # get a random first card my $firstCard = (keys %allCombi)[ int( rand()*$possibleCards ) ]; my %myCards = ($firstCard => 1); delete $allCombi{$firstCard}; # setup referenz map{ $countTerms{$_}++ }(split '-',$firstCard); # setup term counting referenz # creating cards my $card = 1; while ( $card < $cardNo) { # setting up a lookup for rare terms my @rareTerms = sort{ $countTerms{$a} <=> $countTerms{$b} } keys %countTerms; my @newFields = @rareTerms[0..$cardFields-1]; my $newCard = join '-',sort{$a <=> $b}@newFields; my @searchCards = (); # if combination in use, look up a similar combination unless ( exists $allCombi{$newCard} ) { $newCard = ''; while ( scalar @newFields > 0 ) { # spätestens wenn alle Begriffe entfernt wurden, # sollte es eigentlich # irgendeine Kombination finden. - so werden dann hoffentlich # die Bedingungen für die seltensten Kombinationen im Notfall # neu gemischt. # trotzdem habe ich irgendwie Sorgen wegen einer Endlosschleife pop @newFields; my $searchCard = join '-',sort{$a <=> $b}@newFields; @searchCards = grep{/^$searchCard/} keys %allCombi; if ( scalar @searchCards ) { $newCard = $searchCards[0]; last; } } } # found a unused card if ( $newCard ) { $myCards{$newCard} = 1; delete $allCombi{$newCard}; # setup referenz map{ $countTerms{$_}++ }(split '-',$newCard); # setup term counting referenz $card++; } } giveOut(\%myCards); exit 0; #################################### # give out # separiert, da es später ein Modul werden soll sub giveOut { my $myCards = shift; my %usedTerms = (); print '='x40,"\n"; print 'These ',$cardNo,' combinations are selected:',"\n"; foreach my $c ( keys %{$myCards} ) { my @t = map{$terms[$_]}(split '-',$c); print join ',',@t,"\n"; map{ $usedTerms{$_}++ }@t; # count used terms } print "\n",'='x40,"\n"; print 'These terms are in use:',"\n"; foreach my $t ( sort keys %usedTerms ) { print $t,': ',$usedTerms{$t},"x\n" } } Und die Ausgabe dazu: Code: (dl
)
1 frank@Hugin:~/Dokumente/perl/bingo$ ./bingo_math.pl Edit 1: Zusätzliche Fehlerabfrage zur Kontrolle der Startparameter eingefügt. Last edited: 2010-10-03 18:57:46 +0200 (CEST) |