Code technically works but

I’m assuming that this was a typo, and that it should have read ‘here is my final computer BINGO. All I need is to sort the final list of numbers called’. And that is the British ‘sort’ ( meaning to resolve or complete the list of Bingo numbers ) rather than any actually sorting.

I approached this similarly, avoiding a ‘called numbers’ list. But randomizing the entire set of possible bingo calls at the beginning doesn’t seem like the programatic equivalent of pulling balls from the shaker. I decided to ‘remove the balls’ from the list as they are ‘called’. It seemed more in keeping with the game to me.

Here’s another solution to the task. It uses two repeats, but handles the randomisation and sorting in one go if the source list in order. (The numbers in the returned list are in the same order as in the source list.) It relies on the fact that the bingo numbers here are text, whereas the integers used to index them aren’t.

set bingo_numbers to {"B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B09", "B10", "B11", "B12", "B13", "B14", "B15"}
set numberRequired to 8

copy bingo_numbers to called_numbers
repeat with i from 1 to (count called_numbers)
	set item i of called_numbers to i
end repeat
repeat numberRequired times
	set i to some integer of called_numbers
	set item i of called_numbers to item i of bingo_numbers
	display alert (result)
end repeat

return text of called_numbers

Paul, you may be correct, but if so what does the OP mean when he states:

On a side note, after I get the list of numbers called in order, can I sort the list numerically, the variable numbers called

Well done, Nigel! Below is my version, which is similar but not nearly as elegant. By my testing your version is the fastest yet.

set bingo_numbers to {"B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B09", "B10", "B11", "B12", "B13", "B14", "B15"} as list
set countOfBingoNumbers to count of bingo_numbers
set called_numbers to {}
set count_of_called_numbers to 0
set desiredNumber to 8
repeat countOfBingoNumbers times
	set the end of called_numbers to ""
end repeat
repeat
	set randomIndex to random number from 1 to countOfBingoNumbers
	set randomChoice to item randomIndex of bingo_numbers
	if randomChoice is not in called_numbers then
		set item randomIndex of called_numbers to randomChoice
		set count_of_called_numbers to count_of_called_numbers + 1
	end if
	if count_of_called_numbers = desiredNumber then exit repeat
end repeat
set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {" "}
set called_numbers to words of (text items of called_numbers as text)
set AppleScript's text item delimiters to saveTID

I did a bit of reading on the Bingo game, and all Bingo numbers consist of one letter of the word Bingo-- followed by the number 01 to 15 for the letter B, 16 to 30 for the letter I, and so on. As a result, it makes better sense not to do a traditional sort and instead to return all “B” Bingo numbers with a numerical sub-sort, followed by all “I” Bingo numbers with a numerical subsort, and so on. If one uses a list of all 75 Bingo numbers in their correct order, that’s exactly what Nigel’s script does.

However, the game appears to continue until someone yells “Bingo”, and imposing an 8-number limit would seem inadvisable. So, my modification of Nigel’s script is:

set bingo_numbers to {"B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B09", "B10", "B11", "B12", "B13", "B14", "B15", "I16", "I17", "I18", "I19", "I20", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "N31", "N32", "N33", "N34", "N35", "N36", "N37", "N38", "N39", "N40", "N41", "N42", "N43", "N44", "N45", "G46", "G47", "G48", "G49", "G50", "G51", "G52", "G53", "G54", "G55", "G56", "G57", "G58", "G59", "G60", "O61", "O62", "O63", "O64", "OG5", "O66", "O67", "O68", "O69", "070", "071", "072", "073", "074", "075"}

copy bingo_numbers to called_numbers
set bingo_numbers_count to (count bingo_numbers)
repeat with i from 1 to bingo_numbers_count
	set item i of called_numbers to i
end repeat
repeat bingo_numbers_count times
	set i to some integer of called_numbers
	set item i of called_numbers to item i of bingo_numbers
	set buttonReturned to button returned of (display alert (result) buttons {"End", "Continue"})
	if buttonReturned is "End" then exit repeat
end repeat

return text of called_numbers

It’s like the Lottery. Each player’s card only contains a subset of the possible numbers.

But I think the point of the task may have been lost in all the different contributions and healthy discussion its inspired here. Shawn’s “final computer BINGO” does indeed select all seventy-five items from the source list in a random order, the fact that dialogs were only appearing for a subset of them being a bug in the original script. But in post #4, he also asks how to sort the returned list. Clearly it would be simpler just to sort the original list. So the random selection and the sorting could be separate coding exercises on his part rather than an attempt to produce an integrated and actually useful script.

Thanks Nigel. I agree wholeheartedly that this is a coding exercise only, and hopefully we will hear back from Shawn as to his sorting requirements.

Once again as a coding exercise, I couldn’t help but wonder how one might script a Bingo card, and I have included my suggestion below. The timing result was one millisecond.

set theColumns to getColumns()
set bingoCard to getBingoCard(theColumns)

on getColumns()
	set theColumns to {}
	repeat with i from 1 to 61 by 15
		set aColumn to {}
		repeat with j from i to i + 14
			set end of aColumn to j
		end repeat
		set aColumn to getShuffledColumn(aColumn)
		set end of theColumns to aColumn
	end repeat
	set item 3 of item 3 of theColumns to "**" -- "**" is a free square
	return theColumns
end getColumns

on getBingoCard(theList)
	set text item delimiters to {" "}
	set theString to "B   I   N   G   O" & linefeed
	repeat with i from 1 to 5
		set aList to {}
		repeat with j from 1 to 5
			set end of aList to item i of item j of theList
		end repeat
		set theString to theString & (aList as text) & linefeed
	end repeat
	set text item delimiters to {""}
	return theString
end getBingoCard

on getShuffledColumn(theNumbers)
	set shuffledNumbers to {}
	repeat until (count shuffledNumbers) is 5
		set aNumber to (text -2 thru -1 of ("0" & (some item of theNumbers)))
		if aNumber is not in shuffledNumbers then set end of shuffledNumbers to aNumber
	end repeat
	return shuffledNumbers
end getShuffledColumn

Indeed. This script (refined from @robertfern script) properly selects 8 random items from 15 element list. But, still your script in post #3 gives the exact mathematical solution + better speed than all others. Also, I don’t understand why it is faster than other plain AppleScript solutions. I tested without display alert.

This does sound like a request for an actual sort.

In Bingo, once someone calls out “BINGO!” the “dealer” has to confirm that the card column/row/etc matches the called numbers. The claimant calls out each of their matched values and the dealer compares these to the called values. A sorted list of the called values would aid in this check.

1 Like

Hi KniazidisR.

I hadn’t tested any of the scripts for speed. But the post #3 script (simply a fix for Shawn’s in post #1) uses AppleScript’s built-in some specifier to make the random choices, whereas many of the other contributions use the StandardAdditions’s random number command. Being built-in, some executes faster than a call to an OSAX, where communication time’s a factor. But it’s limited to choosing items from lists and doesn’t generate actual numbers like random number does. Nor can the range from which the choice is made be specified.

The beauty of Nigel’s last version and mine is that the list is populated in order so there’s no need for sorting. (Nigel’s does it better and faster).

Here’s a different, but similar script.

This one builds a deck of cards, shuffles it, then deals seven five-card hands


set handSize to 5
set numberOfHands to 7

set unShuffledDeck to DeckOfCards()
set shuffledDeck to ShuffleDeck(unShuffledDeck)
set theHands to DealTheCards(shuffledDeck, handSize, numberOfHands)

on DealTheCards(shuffledDeck, handSize, numberOfHands)
   set theHands to {}
   repeat numberOfHands times
      set the end of theHands to {}
   end repeat
   set x to 1
   repeat handSize times
      set y to 1
      repeat numberOfHands times
         set the end of item y of theHands to item x of shuffledDeck
         set x to x + 1
         set y to y + 1
      end repeat
      
   end repeat
   return theHands
end DealTheCards

on ShuffleDeck(unShuffledDeck)
   copy unShuffledDeck to blankDeck
   
   repeat with i from 1 to (count unShuffledDeck)
      set item i of blankDeck to i
   end repeat
   set x to 0
   set shuffledDeck to {}
   repeat 52 times
      set x to x + 1
      set i to some integer of blankDeck
      set item i of blankDeck to ""
      set thisCard to item i of unShuffledDeck
      set the end of shuffledDeck to thisCard
   end repeat
   
   return text of shuffledDeck
end ShuffleDeck

on DeckOfCards()
   set cardSuits to words of "Clubs Diamonds Hearts Spades"
   set theDeck to {}
   repeat with thisSuit in cardSuits
      set x to 1
      repeat 13 times
         if x = 1 then
            set thisCard to "Ace"
         else if x = 11 then
            set thisCard to "Jack"
         else if x = 12 then
            set thisCard to "Queen"
         else if x = 13 then
            set thisCard to "King"
         else
            set thisCard to x as text
         end if
         set thisCard to thisCard & " of " & thisSuit
         set the end of theDeck to thisCard
         set x to x + 1
      end repeat
   end repeat
   
   return theDeck
end DeckOfCards

But randomizing the entire set of possible bingo calls at the beginning doesn’t seem like the programatic equivalent of pulling balls from the shaker

Why not? at least from a end-result perspective they are the same.

My script essentially puts all the balls in a random order, then pops them off one by one - essentially saying ‘this is the order the balls are going to come out in’
A ‘traditional’ model pulls the balls out one at a time. In a physical world you know the ball hasn’t been used before, and can’t be used again, but that’s not the same with the scripted approaches.

Either way, the result at the end of the day is a randomized order of balls. The difference is that with my approach you know, for sure, that a ball has not been called before, so there’s no extra checking involved.

I have no justification for my perspective on the sorting all the values up-front vs repeatedly selecting random values. There is no testable difference between the two methods. None of this is truly random in any case. I just prefer the real-world-parity of randomly selecting the next value at the time it is needed and removing it from the pool of available choices. I suppose it’s a bit of skeuomorphic programing.

The only functional difference in the two methods that I can conceive of is that one has predetermined and stored the results. Bingo hackers could exploit this! I know that is ridiculous, but I did enjoy typing “Bingo hackers”!

Bingo hackers aside, I’m too lazy to type in all 75 bingo numbers.

So here’s Nigel’s solution with the numbers generated automatically.

If I were doing this for real (setting up an AppleScript bingo game) I would use myriad tables and display the updated called numbers with every draw. (Rows would be numbers called, columns would be “B I N G O”

Buttons would be Call Next Number and “BINGO” (if someone calls Bingo there would be an option to continue (false bingo), quit or start a fresh round)

set numberRequired to 25
set bingo_numbers to GetBingoNumbers()
copy bingo_numbers to called_numbers
repeat with i from 1 to (count bingo_numbers)
	set item i of called_numbers to i
end repeat

repeat numberRequired times
	set i to some integer of called_numbers
	set item i of called_numbers to item i of bingo_numbers
end repeat

return text of called_numbers

on GetBingoNumbers()
	set bingoLetters to characters of "BINGO"
	set bingoNumbers to {}
	set x to 0
	
	repeat with thisLetter in bingoLetters
		repeat 15 times
			set x to x + 1
			set the end of bingoNumbers to thisLetter & "-" & x as text
		end repeat
	end repeat
	
	return bingoNumbers
end GetBingoNumbers

Good ideal with a continuation option Ed!

Compact Bingo caller with sorted Bingo confirmation dialog and resumable calling after a false Bingo.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "GameplayKit"
use scripting additions

set randomSource to current application's GKARC4RandomSource's new()
set bingoCalls to (randomSource's arrayByShufflingObjectsInArray:{"B - 1", "B - 2", "B - 3", "B - 4", "B - 5", "B - 6", "B - 7", "B - 8", "B - 9", "B - 10", "B - 11", "B - 12", "B - 13", "B - 14", "B - 15", "I - 16", "I - 17", "I - 18", "I - 19", "I - 20", "I - 21", "I - 22", "I - 23", "I - 24", "I - 25", "I - 26", "I - 27", "I - 28", "I - 29", "I - 30", "N - 31", "N - 32", "N - 33", "N - 34", "N - 35", "N - 36", "N - 37", "N - 38", "N - 39", "N - 40", "N - 41", "N - 42", "N - 43", "N - 44", "N - 45", "G - 46", "G - 47", "G - 48", "G - 49", "G - 50", "G - 51", "G - 52", "G - 53", "G - 54", "G - 55", "G - 56", "G - 57", "G - 58", "G - 59", "G - 60", "O - 61", "O - 62", "O - 63", "O - 64", "O - 65", "O - 66", "O - 67", "O - 68", "O - 69", "O - 70", "O - 71", "O - 72", "O - 73", "O - 74", "O - 75"}) as list
repeat with i from 1 to length of bingoCalls
	set bingoCallResults to button returned of (display dialog return & return & tab & tab & tab & tab & tab & tab & item i of bingoCalls & return & return buttons {"BINGO!", "Call Again"} default button "Call Again")
	if bingoCallResults is "BINGO!" and checkBingo(i, bingoCalls) is true then exit repeat
end repeat

on checkBingo(i, bingoCalls)
	set theArray to arrayWithArray_(items 1 thru i of bingoCalls) of NSArray of current application
	set calledBingoNumbers to (sortedArrayUsingSelector_("localizedStandardCompare:") of theArray) as list
	set AppleScript's text item delimiters to return
	if button returned of (display dialog "Called bingo numbers:" & return & return & calledBingoNumbers as text buttons {"We have a winner", "false positive"} default button "false positive") is "We have a winner" then return true
	return false
end checkBingo
1 Like

thank you everyone for all the help, here is one more problem
I have the random choice, says its B6
I look in a folder for a graphic named B6.jpg
all I need to do it OPEN the B6.jpg…this code is not working,

	tell application "Finder"
		set this_ball to every item in folder GFX_FOLDER whose name starts with randomChoice
		-- this_ball = "Macintosh HD:Users:shawnbrady:Desktop:Bingo Balls GFX:B11.jpg"
		-- open file this_ball  DOES NOT WORK
	end tell

 

tell application "Finder"
	open document file (randomChoice & ".jpg") of folder "Bingo Balls GFX" of desktop
end tell

 

it tells me I dont have permission, I DO, I open GET INFO, I have permission, what the…