Tequilalime
Tequilalime

Reputation: 621

Bingo Algorithm in C#

I'm trying to create a bingo card which should be set up with the following rules:

So far I've managed to create a card that contains 9 columns and 3 rows and filled the card with unique random numbers but I can't figure out how to achieve 3rd and 4th rules.

In the end, a bingo card should look similar to this:

1     EMPTY   18     EMPTY   12     EMPTY     40    EMPTY 32

EMPTY 2       EMPTY  EMPTY   67     33        EMPTY 44    EMPTY

90    EMPTY   79     EMPTY   38     EMPTY     55    EMPTY 71

In my algorithm I don't know how to put EMPTY blocks and avoid repeating them more than twice

My card generator function is:

public GameCard GetCard()
    {
        //This is the list of all numbers between 1 and 99
        var availableNumbers = Enumerable.Range(CARD_NUM_MIN, CARD_NUM_MAX).ToList();
        var card = new GameCard();

        //looping for 9 columns
        for (var col = 0; col < CARD_COL_COUNT; col++)
        {
            var cardColumn = new CardColumn();

            //looping for 3 rows in each column
            for (var row = 0; row < CARD_ROW_COUNT; row++)
            {
                var cardRow = new NumberBlock();

                //getting a random number from availableNumbers and removing that number from list to avoid duplicate numbers.
                var rand = RandomNumberGenerator.Instance.Next(availableNumbers.Count - 1);
                cardRow.Value = availableNumbers[rand];
                availableNumbers.RemoveAt(rand);

                //I believe somewhere here I should check if there will be more than 5 numbers in a row, or should randomly generate empty blocks? Can't really figure out...
                cardColumn.Rows.Add(cardRow);
            }

            card.Columns.Add(cardColumn);
        }

        return card;
    }

GameCard class:

public class GameCard
{
    public string CardId { get; set; }
    public List<CardColumn> Columns { get; set; }

    public GameCard()
    {
        Columns = new List<CardColumn>();
    }
}

CardColumn class

public class CardColumn
{
    public int Count { get; set; }
    public List<NumberBlock> Rows { get; set; }

    public CardColumn()
    {
        Rows = new List<NumberBlock>();
    }
}

NumberBlock class

public class NumberBlock
{
    public int Value { get; set; }
    public bool IsBlank { get; set; }

    public NumberBlock()
    {
        IsBlank = false;
    }
}

Upvotes: 1

Views: 5674

Answers (1)

Nikki Locke
Nikki Locke

Reputation: 2951

First do some research - there are 45 possible types of row

  91=Number Number Empty  Number Number Empty  Number Empty  Empty  
 107=Number Number Empty  Number Empty  Number Number Empty  Empty  
 109=Number Empty  Number Number Empty  Number Number Empty  Empty  
 155=Number Number Empty  Number Number Empty  Empty  Number Empty  
 171=Number Number Empty  Number Empty  Number Empty  Number Empty  
 173=Number Empty  Number Number Empty  Number Empty  Number Empty  
 179=Number Number Empty  Empty  Number Number Empty  Number Empty  
 181=Number Empty  Number Empty  Number Number Empty  Number Empty  
 182=Empty  Number Number Empty  Number Number Empty  Number Empty  
 203=Number Number Empty  Number Empty  Empty  Number Number Empty  
 205=Number Empty  Number Number Empty  Empty  Number Number Empty  
 211=Number Number Empty  Empty  Number Empty  Number Number Empty  
 213=Number Empty  Number Empty  Number Empty  Number Number Empty  
 214=Empty  Number Number Empty  Number Empty  Number Number Empty  
 217=Number Empty  Empty  Number Number Empty  Number Number Empty  
 218=Empty  Number Empty  Number Number Empty  Number Number Empty  
 299=Number Number Empty  Number Empty  Number Empty  Empty  Number 
 301=Number Empty  Number Number Empty  Number Empty  Empty  Number 
 307=Number Number Empty  Empty  Number Number Empty  Empty  Number 
 309=Number Empty  Number Empty  Number Number Empty  Empty  Number 
 310=Empty  Number Number Empty  Number Number Empty  Empty  Number 
 331=Number Number Empty  Number Empty  Empty  Number Empty  Number 
 333=Number Empty  Number Number Empty  Empty  Number Empty  Number 
 339=Number Number Empty  Empty  Number Empty  Number Empty  Number 
 341=Number Empty  Number Empty  Number Empty  Number Empty  Number 
 342=Empty  Number Number Empty  Number Empty  Number Empty  Number 
 345=Number Empty  Empty  Number Number Empty  Number Empty  Number 
 346=Empty  Number Empty  Number Number Empty  Number Empty  Number 
 357=Number Empty  Number Empty  Empty  Number Number Empty  Number 
 358=Empty  Number Number Empty  Empty  Number Number Empty  Number 
 361=Number Empty  Empty  Number Empty  Number Number Empty  Number 
 362=Empty  Number Empty  Number Empty  Number Number Empty  Number 
 364=Empty  Empty  Number Number Empty  Number Number Empty  Number 
 403=Number Number Empty  Empty  Number Empty  Empty  Number Number 
 405=Number Empty  Number Empty  Number Empty  Empty  Number Number 
 406=Empty  Number Number Empty  Number Empty  Empty  Number Number 
 409=Number Empty  Empty  Number Number Empty  Empty  Number Number 
 410=Empty  Number Empty  Number Number Empty  Empty  Number Number 
 421=Number Empty  Number Empty  Empty  Number Empty  Number Number 
 422=Empty  Number Number Empty  Empty  Number Empty  Number Number 
 425=Number Empty  Empty  Number Empty  Number Empty  Number Number 
 426=Empty  Number Empty  Number Empty  Number Empty  Number Number 
 428=Empty  Empty  Number Number Empty  Number Empty  Number Number 
 434=Empty  Number Empty  Empty  Number Number Empty  Number Number 
 436=Empty  Empty  Number Empty  Number Number Empty  Number Number 

The LinqPad script I used to generate this list is:

List<bool []> permutations = new List<bool []>();

void Main()
{
    // Generate all possible permutations of 9 items
    // 511 is 9 1-bits
    for(uint n = 0; n < 512; n++) {
        bool [] p = perm(n);
        if(valid(p)) {
            permutations.Add(p);
            Console.Write("     {0}=", n);
            for(int i = 0; i < 9; i++)
                Console.Write(p[i] ? "Number " : "Empty  ");
            Console.WriteLine();
        }
    }
}

// Convert a number into a bit pattern (array of 9 bools)
// Representing number (true) or gap (false)
bool [] perm(uint n) {
    bool [] result = new bool[9];
    uint m = 1;
    for(int i = 0; i < 9; m <<= 1, i++)
        result[i] = (n & m) != 0;
    return result;
}

// See if a bit pattern satisfies the rules
bool valid(bool [] p) {
    int repeat = 0;     // Number of trues (numbers) or falses (gaps)
    int count = 0;      // Number of trues (numbers)
    bool last = false;
    for(int n = 0; n < 9; n++) {
        bool current = p[n];
        if(current == last) {
            // This is the same as the last one (i.e. both numbers or both gaps)
            if(++repeat > 2)
                return false; // May not have more than 2 of the same together
        } else {
            repeat = 1;
        }
        if(current)
            count++;
        last = current;
    }
    return count == 5;
}

You could proceed from there - First generate 15 different random numbers from your list, then for each row, randomly choose one of the 25 possibilities, and finally fill the row with numbers.

Far better to do this by row, rather than column, because all your rules apply to rows. If you really need things in columns, switch them round at the end.

Upvotes: 5

Related Questions