Thread Bingokarten erstellen (11 answers)
Opened by frankes at 2010-09-27 22:19

frankes
 2010-10-03 17:42
#141664 #141664
User since
2005-04-02
140 Artikel
BenutzerIn

user image
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
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
frank@Hugin:~/Dokumente/perl/bingo$ ./bingo_math.pl
There are 210 combinations possible.

========================================
These 20 combinations are selected:
term1,term2,term3,term5,term6,term8,
term1,term2,term3,term7,term8,term9,
term3,term4,term7,term8,term9,term10,
term2,term3,term5,term6,term7,term10,
term4,term6,term7,term8,term9,term10,
term2,term3,term4,term6,term8,term9,
term1,term4,term6,term7,term8,term10,
term1,term4,term6,term7,term9,term10,
term1,term4,term5,term7,term8,term10,
term1,term4,term6,term7,term8,term9,
term1,term2,term3,term5,term6,term9,
term1,term2,term4,term5,term6,term7,
term2,term3,term5,term8,term9,term10,
term1,term2,term3,term4,term5,term7,
term2,term3,term5,term7,term9,term10,
term2,term3,term4,term5,term9,term10,
term1,term3,term4,term8,term9,term10,
term1,term2,term5,term6,term8,term9,
term1,term2,term3,term5,term6,term10,
term4,term5,term6,term7,term8,term10,

========================================
These terms are in use:
term1: 12x
term10: 12x
term2: 12x
term3: 12x
term4: 12x
term5: 12x
term6: 12x
term7: 12x
term8: 12x
term9: 12x




Edit 1: Zusätzliche Fehlerabfrage zur Kontrolle der Startparameter eingefügt.
Last edited: 2010-10-03 18:57:46 +0200 (CEST)

View full thread Bingokarten erstellen