Generate Bingo Cards In Many Programming Languages

last modified: February 11, 2007

Here's some programs to generate BuzzwordBingo cards for everyone in your group. We use different buzzwords depending on what kind of meeting we're going to; the examples shown use words for Marketing.


MicrosoftWord Macro

Option Explicit

Private Const USE_WILD = True

Private Const NO_WILD = False

Public Sub MarketingBingoCard()

   Const Count = 25
   Dim Words(Count) As String

   Words(1) = "Synergy"
   Words(2) = "Strategic Fit"
   Words(3) = "Gap Analysis"
   Words(4) = "Best Practice"
   Words(5) = "Bottom Line"
   Words(6) = "Revisit"
   Words(7) = "Bandwidth"
   Words(8) = "Hardball"
   Words(9) = "Out of the Loop"
   Words(10) = "Benchmark"
   Words(11) = "Value-Added"
   Words(12) = "Proactive"
   Words(13) = "Win-Win"
   Words(14) = "Think Outside the Box"
   Words(15) = "Fast Track"
   Words(16) = "Result-Driven"
   Words(17) = "Empower [or] Empowerment"
   Words(18) = "Knowledge Base"
   Words(19) = "Total Quality [or] Quality Driven"
   Words(20) = "Touch Base"
   Words(21) = "Mindset"
   Words(22) = "Client Focus[ed]"
   Words(23) = "Ball Park"
   Words(24) = "Game Plan"
   Words(25) = "Leverage"

   MakeBingoCard Words(), NO_WILD

End Sub

Private Sub MakeBingoCard(ByRef Words() As String, UseWild As Boolean)

   Dim myRange As Range
   Set myRange = ActiveDocument.Range(Start:=ActiveDocument.Range().End - 1, End:=ActiveDocument.Range().End - 1)
   ActiveDocument.Tables.Add Range:=myRange, NumRows:=5, NumColumns:=5

   Dim i As Integer
   Dim j As Integer
   Dim Count As Integer
   Count = UBound(Words)

   Randomize

   For i = 1 To 5

       ActiveDocument.Tables(1).Rows(i).Height = 64

       For j = 1 To 5

           Dim Word As String
           Word = ""

           If UseWild And i = 3 And j = 3 Then
               Word = "*WILD*"
           Else
               Do While Len(Word) = 0
                   Dim WordIndex As Integer
                   WordIndex = Int((Count * Rnd) + 1)
                   If Len(Words(WordIndex)) > 0 Then
                       Word = Words(WordIndex)
                       Words(WordIndex) = ""
                   End If
               Loop
           End If

           With ActiveDocument.Tables(1).Cell(i, j)
               .Range.InsertAfter Word
               .Range.Font.Name = "Arial"
               .Range.Font.Size = 12
               .VerticalAlignment = wdCellAlignVerticalCenter
               .Range.ParagraphFormat.Alignment = wdAlignParagraphCenter
           End With

       Next j
   Next i

End Sub

RubyLanguage

# create a shuffled word list, including wild padding to fill holes
words = ["Synergy","Strategic Fit","Gap Analysis","Best Practice","Bottom Line",
"Revisit","Bandwidth","Hard Ball","Out of the Loop","Benchmark",
"Value-Added","Proactive","Win-Win","Think Outside the Box","Fast Track",
"Result Driven","Empower","Knowledge Base","Total Quality","Mindset",
"Client Focus[ed]","Ball Park","Game Plan","Leverage","Utilize",
"Irregardless","Self-Starter"]
numberOfColumns = 5
(numberOfColumns - words.size()%numberOfColumns).times { words << "Wild!"},

#thanks to http://wiki.rubygarden.org/Ruby/page/show/ArrayShuffle
class Array
  def shuffle
   each_index {|j| i = rand(size-j); self[j], self[j+i] = self[j+i], self[j]},
  end
end 
srand = Time.now.to_i #seems to be a good enough seed
words.shuffle

#come up with some lines and values to make the table print cleanly
columnWidth = 0
words.each{|word|
    if( word.length > columnWidth) then columnWidth = word.length  end
},
totalPadding = 2
columnWidth = columnWidth + totalPadding
header = "."
footer = "'"
midline = " "
numberOfColumns.times {
    columnWidth.times { header << "-"
                        footer << "-"
                        midline << "-"
    },
    header << "."
    footer << "'"
    midline << " "
},

# create the card
File.open("bingoCard.txt","w") do |outFile|
    columnCount = 0

    outFile << header << "\n"

    #prints the word, along with horizontal padding and separators
    words.each {|word|
        if(5 <= columnCount)
         outFile << "|\n"
         outFile << midline << "\n"
         columnCount = 0
        end
        needToFill = columnWidth - word.length
        leftFill = needToFill/2
        rightFill = leftFill + (needToFill%2)

        outFile << "|"
        leftFill.times{ outFile << " " },
        outFile << "#{word},"
        rightFill.times{ outFile << " " },

        columnCount = columnCount + 1
    },

    outFile << "|\n" << footer
end

Small differences include using Wild! as a filler, rather than optional. This allows wordlists to be of 'unaligned' size. I didn't bother with vertical pretty printing, so I shaved some buzzword names.

Even this small task kept hitting me over the head with CreepingFeaturitis (especially prettier printing and word list management) and the urge to further generalize and objectify. Doctor Yagni, I need a pill, please.

Why *that* shuffle? I love sort_by{rand}, :)

sort_by{rand}, is nicer. I'm still getting used to Ruby and didn't know that was an option. I even missed the giant notice at the top of the page explaining the sort I did use trying to educate me about about sort_by{rand},. Oh, and anyone who lets the browser do the table layout for them is a pansy ;)


A nicer, more idiomatic RubyLanguage script:

WORDS = [
"Synergy",         "Strategic Fit",        "Gap Analysis",      "Best Practice",
"Bottom Line",     "Revisit",              "Bandwidth",         "Hard Ball",
"Out of the Loop", "Benchmark",            "Value-Added",       "Proactive",
"Win-Win",         "Think Outside the Box","Fast Track",        "Result Driven",
"Empower",         "Knowledge Base",       "Total Quality",     "Mindset",
"Client Focus[ed]","Ball Park",            "Game Plan",         "Leverage",
"Utilize",         "Irregardless",         "Self-Starter",
]

COLUMNS = 5

words = WORDS.dup
words << "Wild!"  until (words.size % COLUMNS).zero?
words = words.sort_by { rand },

pad = words.map { |w| w.size },.max + 2
words.map! { |w| w.center pad },

def seperator(pad, string)
  string + Array.new(COLUMNS) { "-" * pad },.join(string) + string
end

head = seperator pad, "."
line = seperator pad, " "
foot = seperator pad, "'"

puts head
(words.size / COLUMNS).times { |a|
  puts line  unless a.zero?
  print "|"
  COLUMNS.times { |b|
    print words[COLUMNS*a + b], "|"
  },
  puts
},
puts foot

Should output the same as above Ruby script.


This seems like a good candidate for DivisionOfLabor. The following PerlLanguage script produces HyperTextMarkupLanguage. I mussed with this for List::Util::shuffle.

#!/usr/bin/perl                                                        
use List::Util qw(shuffle);                                            

open(WORDS, "bingo.dat") || die("Can't open bingo.dat");               
@allwords = <WORDS>;                                                   
close(WORDS);                                                          

$rows = 5;                                                             
$cols = 5;                                                             

@shuffled = shuffle(@allwords);                                        

sub getword {                                                          
       $word = pop(@shuffled);                                         
       chomp($word);                                                   
       $word;                                                          
},                                                                      

print "<table border=1>\n";                                            

for (1..$rows) {                                                       
  print "  <tr>\n";                                                    
  for(1..$cols) {                                                      
    my $word = getword();                                              
    print "    <td align=center width=100 height=100>$word</td>\n"     
  },                                                                    
  print "  </tr>\n";                                                   
},                                                                      

print "</table>\n";                                                    

PythonLanguage:

import random
import os

class CardMaker(object):
   # Tweaked so that it will fit in 80 columns...
   words = ["Synergy", "Strategic Fit", "Gap Analysis", "Best Practice",
            "Bottom Line", "Revisit", "Bandwidth", "Hardball", "The Loop",
            "Benchmark", "Value-Add", "Proactive", "Win-Win",
            "Think Big", "Fast Track", "Result-Driven", "Empower",
            "Knowledge Base", "Total Quality", "Touch Base", "Mindset",
            "Client Focus", "Ball Park", "Game Plan", "Leverage"]
   maxlen = max([len(w) for w in words])
   row = "|" + ("%%%ss|"%maxlen)*5 +"\n"
   spacer = "+" + ("-"*maxlen + "+")*5 + "\n"
   template = (spacer + row)*5 + spacer

   def __call__(self, use_wild=False, template=None):
       if not template:
           template = self.template
       words = self.words[:]
       random.shuffle(words)
       if use_wild:
           words[12] = "*WILD*"
       return template % tuple(words)

Quick and dirty usage examples - may need to fix file paths:

def make_one_file():
   make_card = CardMaker()
   people = ["John", "Jane", "Sally", "Mark"]
   f = open("C:/bingo.txt", "w")
   for person in people:
       print>>f, "%s:"%person
       print>>f, make_card(use_wild=True)
make_one_file()

def make_one_webpage():
   row = "<tr>" + "<td align=center width=100 height=100>%s</td>"*5 + "</tr>"
   template = "<HTML><table border=1>" + row*5 + "</table>"+"</HTML>"

   make_card = CardMaker()
   print>>open("C:/bingo.htm", "w"), make_card(template=template)
make_one_webpage()

CommonLisp:

(use-package :com.gigamonkeys.html)

(defparameter *phrases*
  #("Synergy" "Strategic Fit" "Gap Analysis" "Best Practice" "Bottom Line"
    "Revisit" "Bandwidth" "Hardball" "Out of the Loop" "Benchmark" "Value-Added"
    "Proactive" "Win-Win" "Think Outside the Box" "Fast Track" "Result-Driven"
    "Empower [or] Empowerment" "Knowledge Base" "Total Quality [or] Quality Driven"
    "Touch Base" "Mindset" "Client Focus[ed]" "Ball Park" "Game Plan" "Leverage"))

(defun randomize (vector)
  (loop for i from (length vector) downto 1
        do (rotatef (aref vector (1- i))
                    (aref vector (random i))))
  vector)

(defun print-bingo-card (phrases row-length)
  (when (< (length phrases) (expt row-length 2))
    (error "Only received ~S phrases. Need at least ~S." 
           (length phrases) (expt row-length 2)))
  (html
    (:html ((:table :border 1)
            (loop with index = 0
                  with random-phrases = (randomize (copy-seq phrases))
                  repeat row-length
                  do (html (:tr
                            (loop repeat row-length 
                                  do (html ((:td :align :center :width 100 :height 100)
                                            (:format "~A" (svref random-phrases index))))
                                  do (incf index)))))))))

(print-bingo-card *phrases* 5)

Things to keep in mind:


CeePlusPlus:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
using namespace std;

int main(int argc, char **argv){
  vector<string> words;
  ifstream in("bingo.dat");
  string line;
  while(getline(in, line)) 
    words.push_back(string(line));
  srand(time(0));
  random_shuffle(words.begin(), words.end()); 

  cout << "<html><head><title>Buzzword Bingo</title>" << endl
    << "<style>td { text-align: center; width: 6em; height: 6em; border: solid 2px black }, </style>" << endl 
    << "</head><body><table>" << endl;

  for(int row = 0; row < 5; row++){
    cout << "<tr>" << endl;  
    for(int col = 0; col < 5; col++){
      cout << "<td>" 
        << (row == 2 && col == 2 ? "FREE" : words[row * 5 + col]) 
        << "</td>" << endl;
    },
    cout << "</tr>" << endl;  
  },
  cout << "</table></body></html>" << endl;
},

OcamlLanguage:

open Printf

    let phrases =
 ["Synergy"; "Strategic Fit"; "Gap Analysis"; "Best Practice";
  "Bottom Line"; "Revisit"; "Bandwidth"; "Hardball"; "Out of the Loop";
  "Benchmark"; "Value-Added"; "Proactive"; "Win-Win";
  "Think Outside the Box"; "Fast Track"; "Result-Driven"; "Empower[ment]";
  "Knowledge Base"; "Total Quality"; "Touch Base";
  "Mindset"; "Client Focus[ed]"; "Ball Park"; "Game Plan"; "Leverage"]

    let max_phrase_length =
 (List.fold_left
    (fun max str ->
      let len = (String.length str) in
      if len > max then len else max)
    0 phrases) + 3

    let list_extract_nth list n =
 let rec continue list acc n =
   match n, list with
     (_, []) -> raise (Failure "nth")
   | (0, hd :: tl) -> (hd, (List.rev_append acc tl))
   | (_, hd :: tl) -> continue tl (hd :: acc) (pred n)
 in continue list [] n

    let shuffle list =
 let rec continue list acc n =
   match n with
     0 -> acc
   | _ ->
       let i = (Random.int n) in
       let (elt, rest) = (list_extract_nth list i) in
       continue rest (elt :: acc) (pred n)
 in continue list [] (List.length list)

    let matrix_of_list list x y =
 let array = Array.of_list list and matrix = Array.make x [||] in
 let _ = for i = 0 to x-1 do matrix.(i) <- Array.sub array (i*y) y done in
 matrix

    let print_bingo use_wild width matrix =
 Array.iteri (fun i row -> begin
   Array.iteri (fun j cell -> begin
     let string = 
       match (i, j, use_wild) with
         (2, 2, true) -> "*WILD*" | _ -> cell
     in printf "%*s" width string
   end) row;
   print_endline "";
 end) matrix
    ;;

    let _ = Random.self_init () in
    (print_bingo true max_phrase_length (matrix_of_list (shuffle phrases) 5 5))

See: CategoryInManyProgrammingLanguages, ProgrammingChrestomathy


Loading...