Permalänk
Medlem

Enkelt bingo-program

Kort bakgrund: jag jobbar på ett äldreboende, och någon/några gånger i veckan anordnar personalen bingo för de boende som vill vara med. Till buds har vi en påse med numrerade kulor (1 till 75), och även några handskrivna lappar för de nummer vars kulor tyvärr gått förlorade under åren.

Nu har jag fått för mig att försöka eliminera det första steget, det som involverar påsen med kulorna, genom att skriva ett program som sköter den delen. Jag tänkte använda mig av Python, men språket kvittar egentligen eftersom jag inte är ute efter ett färdigt program. Jag är mest nyfiken på hur mer erfarna programmerare skulle tackla uppgiften.

Min första tanke var att bara slumpa fram tal, mellan 1 och 75 i det här fallet, och samtidigt lägga till det slumpade talet i en lista (som de används i Python), och varje följande gång när ett tal slumpas kontrollera att det inte redan finns i listan för använda tal - och i så fall slumpa ett nytt tal - innan det läggs till listan.

Men, det känns inte särskilt "cleant".. så, min nästa tanke var att inleda med att skapa en lista med talen 1 till 75 (med en for loop), sedan slumpa fram en av posterna (index 0 till 74 blir det ju i Python) och printa den och sedan ta bort den från listan, och i nästa runda slumpa (0, 73) i stället, dvs minska indexet med 1 för varje gång ett nummer dras.

Borde funka, meeeen.. finns det någon ännu mer elegant lösning? Diskutera.

Permalänk
Rekordmedlem

En lista med nummren som sorteras slumpmässigt och sedan läser man av den från ena änden.

Visa signatur

R5 5600G, Asus ROG STRIX X470-F Gaming, WD SN850X 2TB, Seasonic Focus+ Gold 650W, Aerocool Graphite v3, Tittar på en Acer ET430Kbmiippx 43" 4K. Lyssnar på Behringer DCX2496, Truth B3031A, Truth B2092A. Har också oscilloskop, mätmikrofon och colorimeter.

Permalänk
Medlem
Skrivet av PHJ:

Men, det känns inte särskilt "cleant".. så, min nästa tanke var att inleda med att skapa en lista med talen 1 till 75 (med en for loop), sedan slumpa fram en av posterna (index 0 till 74 blir det ju i Python) och printa den och sedan ta bort den från listan, och i nästa runda slumpa (0, 73) i stället, dvs minska indexet med 1 för varje gång ett nummer dras.

Låter bra, slumpa fram index mellan 0 och antalet objekt i listan - 1.

Permalänk
Medlem

Hade också bara slumpat listan 1 gång och läst av i ordning. Får ju samma effekt, men enklare.
När man har den slumpade listan kan man enkelt läsa och ta bort värdet (sista i listan) med:

bingo.pop() // returnerar sista värdet i listan och tar bort det

eller

bingo.popleft() // returnerar första värdet i listan och tar bort det

https://docs.python.org/3/tutorial/datastructures.html#using-...

Permalänk
Medlem

Det lättaste sättet att göra någonting sådant här är som @mrqaffe säger att ta fram en lista med alla talen i ordning och sedan skyffla om den listan, varpå du sedan går igenom listan från start till slut.

Här har du ett minimalt program som gör det (inom spoiler-taggar om det var så att du ville få sitta och klura på implementationen själv):

import random numbers = list(range(1, 76)) random.shuffle(numbers) for number in numbers: print(number)

Minsta acceptabla interaktivitet är kanske att dragningen väntar tills du trycker ENTER, det kan ordnas på följande sätt.

import random numbers = list(range(1, 76)) random.shuffle(numbers) for number in numbers: input('Press ENTER to draw a number') print(number)

Dold text

Det är inte jättesvårt att slänga på ett minimalt GUI på det om åldringarna ska få se lite fårgglada cirklar med siffror på, ex. PySimpleGui är väldigt enkelt att använda: https://github.com/PySimpleGUI/PySimpleGUI

Permalänk
Medlem

Haha, jäkla Python alltså, man tror man ska behöva koda lite själv men så finns det redan funktioner för allt. Aja, tack så mycket för input (!) allihop!

Måste ändå tillägga att även om det intellektuellt givetvis är en likvärdig lösning att från början slumpa fram listan och sedan beta av ett värde i taget så är det något på ett känslomässigt plan, nästan själsligt, som skaver.. Lite som The Matrix, hur kan Neo välja vad han ska göra om The Oracle redan vet vad han kommer att göra? o.O Men men, för spelet gör det ju ingen skillnad (och något val är ju inte inblandat i bingo ändå).

Permalänk
Medlem

@PHJ Men dã får vi ju ta och lösa din själsliga kris med en lösning som inte gör valet om vilken nästa siffra är förrän det är dags att dra ett nummer.

Ett tämligen enkelt sätt att göra det är att helt enkelt implementera en shuffle-algoritm (Fisher-Yates Shuffle är både enkel och effektiv), och ge ut en siffra i taget istället för hela listan i ett kör. Det gäller att ha huvudet på skafft när man implementerar något sådant här, då det är väldigt lätt att göra "off-by-one"-fel (ex. så är range-funktionen inklusiv i starten men exklusiv i slutet, medan random.randint är inklusiv i bäda ändarna).

Bara så att jag är tydlig här: detta är en onödigt komplicerad lösning på problemet, då vi egentlig gör precis samma sak (skyfflar om en lista), bara att vi även måste implementera shuffle-algoritmen själva. Men själslig frid måste väl ändå prioriteras?

Givetvis spoiler-taggat så att du kan anta utmaningen själv om du får lust för det.

import random def bingo(): for number in randomly_ordered_range(1, 76): input("Press ENTER to draw a number") print(number) def randomly_ordered_range(start, end): """Return a generator with the values in range(start, end), but in random order. """ if start >= end: raise ValueError(f"requires start < end, got start={start}, end={end}") numbers = list(range(start, end)) length = len(numbers) for i in range(0, length): j = random.randint(i, length - 1) numbers[i], numbers[j] = numbers[j], numbers[i] yield numbers[i] if __name__ == "__main__": bingo()

Det är en liten tvist på Fisher-Yates Shuffle här: vi kör så att `i` faktiskt antar värdet av sista indexet i arrayen, nämligen `length - 1`. Detta är ur skyfflingsperspektiv helt onödigt då `random.randint(length - 1, length - 1)` givetvis bara kan bli `length - 1` så att swappen på andra raden i loopen blir en noop (i == j). Vi gör detta enbart för att enkelt kunna yielda sista värdet i listan.

Dold text

Din föreslagna lösning att ha en lista med värden och en annan med index hade givetvis också fungerat. Men då hade jag inte fått uppleva nostalgin av att implementera Fisher-Yates Shuffle, så jag hade inget egentligt val här.

Permalänk
Medlem

I min mening är det bra att utvärdera hur random olika funktioner är (både färdiga funktioner och funktioner man skriver själv). Dock är det kanske inte lika viktigt för ett sådant projekt du beskriver.

Permalänk
Medlem
Skrivet av SimpLar:

@PHJ Men dã får vi ju ta och lösa din själsliga kris med en lösning som inte gör valet om vilken nästa siffra är förrän det är dags att dra ett nummer.

Ett tämligen enkelt sätt att göra det är att helt enkelt implementera en shuffle-algoritm (Fisher-Yates Shuffle är både enkel och effektiv), och ge ut en siffra i taget istället för hela listan i ett kör. Det gäller att ha huvudet på skafft när man implementerar något sådant här, då det är väldigt lätt att göra "off-by-one"-fel (ex. så är range-funktionen inklusiv i starten men exklusiv i slutet, medan random.randint är inklusiv i bäda ändarna).

Aha, snyggt.