g | x | w | all
Bytes Lang Time Link
105Zsh250223T115457Zroblogic
202APLNARS250222T145450ZRosario
188Kotlin 2.0+250221T092145ZJoon Yor
151Python 3230203T220157ZDaveM552
036Jelly230202T175456ZThe Thon
157Python 3230131T192952ZThe Thon
038Japt mR230131T123507ZShaggy
225C gcc230201T004136ZErikF
094Raku230201T192610ZSean
120Bash + GNU utils230201T173800ZDigital
049Pip230201T162852ZDLosc
132JavaScript ES6230131T094505ZArnauld
03205AB1E230201T074322ZKevin Cr
029Vyxal J230131T081618Zlyxal
046APL Dyalog Extended230131T212637ZAdá
211QBasic230131T204812ZDLosc
039Pyth230131T154423ZCursorCo
123Factor230131T122340Zchunes
049Charcoal230131T100830ZNeil

Zsh, 105 bytes

repeat $1 {A=(B I N G O `(for i ({1..75..15})shuf -i$i-$[i+14] -n5)|rs -t 5`)
A[18]=free;<<<$A|rs 6;echo}

Try it online!

APL(NARS), 202 chars

next←1

r←n rndu w;t
r←∅⋄→0×⍳(w<n)∨(n≤0)∨(w≥1E9)∨w≤0⋄r←⍬
next←2147483648∣12345+next×1103515245
t←1+w∣⌊next÷65536⋄→2×⍳t∊r⋄r,←t⋄→2×⍳0<n-←1

f←{⍪{M←⊃(15×0..4)+{5 rndu ⍵}¨15×⍵⍴1⋄M[3;3]←⊂'free'⋄⍉'BINGO',M}¨⍵⍴5}

//7+13+36+38+41+67 rndu would return n random numbers in 1..w without repetition, or ∅ if n>w. Reference is the function rand in the book "The C Language" Brian W. Kernignan, Dennis M. Ritchie. This seems ok even if I m not 100% sure.

test:

  f 3
 B  I    N  G  O  
 8 26   35 48 74  
 1 17   31 60 67  
12 21 free 47 75  
 7 20   44 58 61  
13 28   42 51 71  
                
 B  I    N  G  O  
 1 28   40 57 64  
10 23   45 55 62  
 9 20 free 52 72  
 3 29   39 48 70  
13 30   34 46 73  
                
 B  I    N  G  O  
10 20   39 59 67  
14 29   42 58 63  
12 23 free 60 68  
 5 25   41 51 72  
 3 21   31 52 66  
  f 1
 B  I    N  G  O  
15 30   34 50 73  
 7 16   44 46 72  
13 24 free 47 67  
 3 18   38 58 69  
10 26   35 52 66  
  

Kotlin 2.0+, 188 bytes

fun b(x:Int)=repeat(x){println("\nB I N G O");val c=List(5){(it*15+1..it*15+15).shuffled().take(5)};repeat(5){i->println((0..4).joinToString(" "){if(i==2&&it==2)"free"else"${c[it][i]}"})}}

Online Test

I take advantage of shuffled() to randomize numbers but not have duplicates, also saves an import of Kotlin's random; aside from that I just print the columns of the 2d vector c but print free if I get to the center of the 2d vector which is c[2][2]

Python 3, 151 bytes

from random import *
print("B I N G O")
x=lambda n:n*15+randint(0,15)
[print(*[*("free"if(i==2 and j==2)else x(j)for j in range(5))])for i in range(5)]

Jelly, 38 36 bytes

75s15Ẋ€ḣ€5Z“ƝM»€3¦€3¦“BINGO”ṭṚK€Y⁷Ṅ)

Try it online!

Most of the credit goes to @cairdcoinheringaahing and @UnrelatedString for helping me in chat.

This can probably be a bit shorter, though.

Explanation

75        # 75 (implicit range)
  s15     # Split into 15 parts
     Ẋ€   # Random permutation of each
ḣ€5       # First 5 elements of each
   Z      # Transpose
    “ƝM»  # Replace ↓ with "free"
€3¦€3¦    # The third item in the third item (1-indexed)
“BINGO”   # Push "BINGO"
       ṭṚ # Append and reverse (i.e. prepend)
K€        # Join each by spaces
  Y⁷      # Join by newlines and append a newline
    Ṅ     # Print
     )    # Repeat input number of times

Python 3, 198 166 157 bytes

lambda n:exec('m=["BINGO",*map(list,zip(*[sample(range(i,i+15),5)for i in range(1,75,15)])),""];m[3][2]="free";[print(*i)for i in m];'*n)
from random import*

Try it online!

(ATO isn't working right now so I switched to TIO)

This can probably be golfed a bit more.

Japt -mR, 39 38 bytes

75õ òF Ëö¤v5Ãg2Èh2`fe`ÃÕi"BINGO"¬ m¸·

Try it

75õ òF Ëö¤v5Ãg2Èh2`fe`ÃÕi"BINGO"¬ m¸·     :Implicit map of range [0,input)
75õ                                        :Range [1,75]
    ò                                      :Partitions of length
     F                                     :  15
       Ë                                   :Map
        ö¤                                 :  Shuffle
          v5                               :  First 5 elements
            Ã                              :End map
             g2                            :Modify the element at 0-based index 2 by
               È                           :Passing it through the following function
                h2                         :  Replace the element at 0-based index 2 with
                  `fe`                     :  Compressed string "free"
                      Ã                    :End modification
                        Õ                  :Transpose
                         i                 :Prepend
                          "BINGO"¬         :  "BINGO", split into an array
                                   m       :Map
                                    ¸      :  Join with spaces
                                     ·     :Join with newlines
                                           :Implicit output joined with newlines

C (gcc), 262 225 bytes

a[6][5]={L"BINGO"};f(n,i,j,k,r){--n&&puts("",f(n));for(j=5;j--;)for(k=i=0;k||++i<6;k||(a[i][j]=r))for(r=j*15+rand(k=i)%15+1;--k&&a[k][j]-r;);for(i=0;i<6;i+=puts(""))for(j=0;j<5;)printf(i*j-9?i?"%d	":"%c	":"free	",a[i][j++]);}

Try it online!

Ungolfed (` used instead of literal tab character):

a[6][5]={L"BINGO"}; // bingo array, with header
f(n, // number of cards to generate
  i,j, // row and column
  k, // random number row checker
  r // random number
 ) {
  --n && puts("",f(n)); // recursively print cards, adding newline
  for(j=5;j--;) // for each column
      for(k=i=0;k||++i<6;k||(a[i][j]=r)) // for each row (redo duplicates)
        for(r=j*15+rand(k=i)%15+1;--k&&a[k][j]-r;); // detect duplicates
    for(i=0;i<6;i+=puts("")) // mark middle item as free; print board
      for(j=0;j<5;)
        printf(i*j-9?i?"%d`":"%c`":"free`",a[i][j++]);
}

Raku, 94 bytes

{join "

",({S:13th/\d+/free/}((<B I N G O>,|[Z] (1..75).rotor(15)».pick(5)).join("
"))xx$_)}

Bash + GNU utils, 120

for((;j++<$1;));{
for((;++i<75;));{
a+=" <(shuf -i$i-$[i+=14] -n5)"
}
eval paste$a|sed '1iB	I	N	G	O
3s/\w*/free/3
$a
'
}

Try it online!

Pip, 50 49 bytes

La{Y ZSH*\,75CH5y@2@2:"free"P_JsPBnMyH5PE"BINGO"}

Attempt This Online!

Explanation

La{...}

Given command-line argument a, loop that many times:

Y ZSH*\,75CH5
      \,75            ; Inclusive range from 1 to 75
          CH5         ; Chop into 5 equal sections
   SH*                ; Randomly shuffle each section
  Z                   ; Transpose
Y                     ; Yank that result into the y variable

y@2@2:"free"          ; Set the element of y at index 2,2 to the string "free"

P_JsPBnMyH5PE"BINGO"
        yH5           ; Take the first 5 elements of y
           PE"BINGO"  ; Prepend the element "BINGO"
       M              ; Map to each:
 _Js                  ;  Join on spaces
    PBn               ;  and push a newline to the end of the resulting string
P                     ; Print that list, concatenated, with a trailing newline

JavaScript (ES6), 132 bytes

f=N=>(F=n=>N?n<30?F[k=n%5]^(F[k]|=1<<(v=Math.random()*15))?(n++-17?"_BINGO"[n]||k*15-~v:'free')+` 
`[k>>2]+F(n):F(n):`
`+f(N-1):n)``

Try it online!

Commented

f = N => (              // outer function taking the number N of grids
  F = n =>              // inner function taking a counter n
  N ?                   // if there's still a grid to process:
    n < 30 ?            //   if n is less than 30:
      F[k = n % 5]      //     k is the column index in [0..4]
      ^                 //     if F[k] is not equal to its updated value
      ( F[k] |= 1 << (  //     where the floor(v)-th bit is set
          v =           //     where v is
          Math.random() //     randomly picked in [0,15[
          * 15          //
      )) ?              //     then:
        ( n++ - 17 ?    //       if this is not the center cell:
            "_BINGO"[n] //         append either a BINGO letter (if n <= 5)
            ||          //         or
            k * 15 - ~v //         the number k * 15 + floor(v + 1)
          :             //       else:
            'free'      //         append the word 'free'
        ) +             //
        ` \n`[k >> 2] + //       append a line-feed if k = 4,
                        //       or a space otherwise
        F(n)            //       append the result of a recursive call to F
      :                 //     else:
        F(n)            //       try again
    :                   //   else:
      `\n` +            //     append a line-feed followed by
      f(N - 1)          //     the result of a recursive call to f
  :                     // else:
    n                   //   stop the recursion
)``                     // initial call to F with n zero'ish

05AB1E, 32 bytes

F75L5äε.r5£N<i'€²2ǝ}}ø‘Èß‘Sš»,¶?

Try it online.

Explanation:

F                # Loop the (implicit) input-integer amount of times:
 75L             #  Push a list in the range [1,75]
    5ä           #  Split it into five equal-sized parts
      ε          #  Map over each part:
       .r        #   Randomly shuffle the list
         5£      #   Then only keep the first 5 integers
       N<i       #   If the index is 2:
          '€²   '#    Push dictionary string "free"
             2ǝ  #    Insert it at (0-based) index 2 into the quintuplet-list
      }}         #  Close both the if-statement and map
        ø        #  Zip/transpose the matrix; swapping rows/columns
         ‘Èß‘    #  Push dictionary string "BINGO"
             S   #  Convert it to a list of characters: ["B","I","N","G","O"]
              š  #  Prepend it to the matrix
               » #  Join each inner list by spaces; and then each string by newlines
 ,               #  Pop and print it with trailing newline
  ¶?             #  And print an additional newline character

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why '€² is "free" and ‘Èß‘ is "BINGO".

Vyxal J, 29 bytes

(‛₆ṫ⇧Ṅ75ɾ15ẇƛÞ℅5Ẏ;∩2≬2‛λċȦV⁋¶

Try it Online!

Explained (old)

(        # input times:
75ɾ15ẇ   #   push the range [1, 75] split into chunks of 15 items
ƛÞ℅5Ẏ;   #   to each: random_permutation[:5]
∩        #   transpose
2≬2‛λċȦV #   tos[2][2] = "free"
‛₆ṫ⇧p    #   .prepend("BINGO")
vṄ⁋      #   .map(" ".join(x)).join("\n")
¶+,      #   + "\n" (then print)

APL (Dyalog Extended), 46 bytes

Full program. Prompts for n.

('BINGO'{'free'}¨@3@4⍤⍪(15×…4)+⍤1⍉)⍤2↑5?¨⎕5⍴15

Try it online!

⎕5⍴15 prompt for n and join that 5, then use that as dimensions for an array of 15s

5?¨ for each 15, get 5 random numbers in the range 1 through that, without replacement

 mix this matrix of lists into an n-by-5-by-5 array with each row being a randome 5-of-15

()⍤2 on each layer:

  transpose, so the 5-of-15 rows become columns

()+⍤1 add the following to each row:

  …4 the numbers 0 through 4

  15× fifteen multiplied by those

'BINGO'⍤⍪ prepend a row of the given letters, then:

  …@4 at row 4:

   …@3 at column 3:

   { replace each value (though there's only one) with:

    'free' the given word

QBasic, 211 bytes

DIM b(5,5)
RANDOMIZE TIMER
INPUT n
FOR i=1TO n
ERASE b
?
?"B","I","N","G","O
FOR r=0TO 4
FOR c=0TO 4
4x=INT((c+RND)*15+1)
FOR p=0TO r
IF x=b(p,c)GOTO 4
NEXT p
IF(r=2)*(c=2)THEN?"free",ELSE?x,:b(r,c)=x
NEXT c,r,i

Try it at Archive.org! Example run:

An example run with input 3, showing 3 randomly generated bingo cards

Explanation/ungolfed

DIM b(5, 5)
RANDOMIZE TIMER
INPUT n

Declare b as a 5x5 array; we'll use this to track already-selected numbers and avoid duplicates. Seed the pseudo-random number generator using the current time. Prompt the user for the number of cards n.

FOR i = 1 TO n

Loop n times:

ERASE b
PRINT
PRINT "B", "I", "N", "G", "O"

Set all values in b to zero. Print a blank line followed by the B I N G O header. The commas in the PRINT statements separate the items by tabs, using a default tab stop of 14 columns.

FOR r = 0 TO 4
FOR c = 0 TO 4

Loop over rows 0 through 4; for each row, loop over columns 0 through 4.

4 x = INT((c + RND) * 15 + 1)

Label this as line number 4, which we'll use as a GOTO target later. Set x to be a random integer, greater than or equal to c*15+1, and less than (c+1)*15+1.

FOR p = 0 TO r
IF x = b(p, c) THEN GOTO 4
NEXT p

Loop over each previous row p. If x equals the value in array b at row p, column c, go back to line 4 and generate a new random number.

IF (r = 2) * (c = 2) THEN
  PRINT "free",
ELSE
  PRINT x,
  b(r, c) = x
END IF

If both r and c are 2, print the string "free"; otherwise, print x and set the appropriate value in the b array to x. In both cases, end the print statement with a tab rather than a newline.

NEXT c, r, i

Close all the FOR loops.


Astute readers may have noticed this doesn't print a newline at the end of each row. Because of the size of the default tab stop, it just so happens that the sixth column wraps to the next line, so printing a newline explicitly is unnecessary (and, in fact, results in unwanted blank lines). This might be bending the I/O requirements a bit. If an explicit newline must be printed, modify the B I N G O line by adding ", at the end, and add a line containing ? in between the FOR r and FOR c headers.

Pyth, 39 bytes

VQkjd"BINGO"jjL\ Cc5X%3s.SMc5S75y6"free

Try it online!

Explanation

                                           # implicitly assign Q = eval(input())
VQ                                         # for N in range(Q):
  k                                        # print a newline
   jd"BINGO"                               # print BINGO joined on spaces
                             S75           # range(1,76)
                           c5              # split into 5 equal parts
                        .SM                # randomly shuffle each part
                       s                   # join the parts back together
                     %3                    # take every third element
                    X           y6"free    # replace the 12th element with "free"
                  c5                       # split into 5 equal parts again
                 C                         # transpose
             jL\                           # join each part on whitespace, converting all elements to strings
            j                              # join on newlines and print

Factor, 123 bytes

[ [ "free"2 75 [1,b] 15 group [ 5 sample ] map flip
[ third set-nth ] keep "BINGO"1 group prefix simple-table. nl ] times ]

Try it online!

"free"                 ! "free"
2                      ! "free" 2
75                     ! "free" 2 75
[1,b]                  ! "free" 2 { 1 2 ... 75 }
15                     ! "free" 2 { 1 2 ... 75 } 15
group                  ! "free" 2 { { 1 2 .. 15 } { 16 17 .. 30 } ... { 61 62 .. 75 } }
[ 5 sample ] map       ! "free" 2 {
                       !     { 9 13 14 1 5 }
                       !     { 26 24 25 27 22 }
                       !     { 32 38 41 31 33 }
                       !     { 54 59 55 49 57 }
                       !     { 75 74 70 71 63 }
                       ! }
flip                   ! "free" 2 {
                       !     { 9 26 32 54 75 }
                       !     { 13 24 38 59 74 }
                       !     { 14 25 41 55 70 }
                       !     { 1 27 31 49 71 }
                       !     { 5 22 33 57 63 }
                       ! }
[ third set-nth ] keep ! {
                       !     { 9 26 32 54 75 }
                       !     { 13 24 38 59 74 }
                       !     { 14 25 "free" 55 70 }
                       !     { 1 27 31 49 71 }
                       !     { 5 22 33 57 63 }
                       ! }
"BINGO"                ! { ... } "BINGO"
1 group                ! { ... } { "B" "I" "N" "G" "O" }
prefix                 ! {
                       !     { "B" "I" "N" "G" "O" }
                       !     { 9 26 32 54 75 }
                       !     { 13 24 38 59 74 }
                       !     { 14 25 "free" 55 70 }
                       !     { 1 27 31 49 71 }
                       !     { 5 22 33 57 63 }
                       ! }
simple-table.          ! output to stdout
nl                     ! newline

Charcoal, 54 52 49 bytes

FN«≔⪪BINGO¹θF²⁵⊞θ⎇⁼κ¹²free‽⁻⁺×¹⁵﹪κ⁵…¹¦¹⁶θ⟦E⪪θ⁵⪫κ 

Try it online! Link is to verbose version of code. Explanation: Now inspired by @Arnauld's answer.

FN«

Input n and loop that many times.

≔⪪BINGO¹θ

Start with a list of BINGO as separate characters which will make up the first row.

F²⁵

Loop 25 times.

⊞θ⎇⁼κ¹²free‽⁻⁺×¹⁵﹪κ⁵…¹¦¹⁶θ

Put the word free in the middle cell, otherwise take a random element of the appropriate numeric range for the cell but subtracting all of the numbers generated so far, and push the result to the list.

⟦E⪪θ⁵⪫κ 

Split into rows of five cells, join the rows on spaces and output the resulting board double-spaced from the next board.