Python Zufallsgenerator: bestimmte Zahlen ausgrenzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

Hi,
ich möchte in einem Zufallsgenerator einen Bereich angeben, aber bestimmte Variablen ausgrenzen.

In meinem Beispiel:
Es wird ein Wert "a" aus 12 zufällig ausgewählt. Im zweiten Durchgang dürfen ein festgelegter Gegenwert "a1" und der Wert "a" nicht mehr vorkommen. Im dritten und letzten Durchgang dürfen "a", "a1", der im zweiten Durchgang generierte Wert "b" und dessen Gegenwert "b1" nicht mehr vorkommen.

Mag ein wenig kompliziert aussehen, aber eigentlich läuft es in den beiden letzten Durchgängen auf dasselbe raus: Ich brauche einen Befehl, der es mir erlaubt, aus einem Bereich im Zufallsgenerator bestimmte Zahlen auszulassen.

Mein erster Ansatz wäre gewesen (nur zum probieren, es müssen ja am Ende mehrere Variablen ausgelassen werden)

Code: Alles auswählen

b2 = random.randint(1,12 != b1)
aber das funktioniert nicht. Kennt jemand eine geeignete Lösung?

Danke im Voraus! ;)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Willkommen im Forum!

Dein Ansatz macht keinen Sinn, weil du da entweder `randint(1, 0)` oder `randint(1, 1)` aufrufst, je nachdem ob `b1 != 12` gilt.

Statt bestimmte Zahlen auszuschliessen, koenntest du erst einen Pool moeglicher Werte bilden und dann bisherige Ergebnisse aus dem Pool ausschliessen, beispielsweise:

Code: Alles auswählen

In [5]: import random      

In [6]: pool = set(range(1, 13))

In [7]: chosen = set()                  

In [8]: for _ in range(3):
    chosen.add(random.choice(list(pool - chosen)))
   ...:     

In [9]: chosen
Out[9]: {4, 7, 8}
Oder du benutzt gleich `random.sample`, wenn du nur `n` Werte aus einer Menge ziehen willst:

Code: Alles auswählen

In [10]: random.sample(range(1, 13), 3)
Out[10]: [5, 1, 9]
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

cofi hat geschrieben:Willkommen im Forum!

Dein Ansatz macht keinen Sinn, weil du da entweder `randint(1, 0)` oder `randint(1, 1)` aufrufst, je nachdem ob `b1 != 12` gilt.

Statt bestimmte Zahlen auszuschliessen, koenntest du erst einen Pool moeglicher Werte bilden und dann bisherige Ergebnisse aus dem Pool ausschliessen, beispielsweise:

Code: Alles auswählen

In [5]: import random      

In [6]: pool = set(range(1, 13))

In [7]: chosen = set()                  

In [8]: for _ in range(3):
    chosen.add(random.choice(list(pool - chosen)))
   ...:     

In [9]: chosen
Out[9]: {4, 7, 8}
Oder du benutzt gleich `random.sample`, wenn du nur `n` Werte aus einer Menge ziehen willst:

Code: Alles auswählen

In [10]: random.sample(range(1, 13), 3)
Out[10]: [5, 1, 9]
Danke für die schnelle Antwort! "random.sample" würde funktionieren, wären da nicht die Gegenwerte. Genauer gesagt sind es 2x6 Werte, bei denen immer zwei aus beiden 6er Packs zusammengehören. Wenn eines bereits zufällig gewählt wurde, kann das andere nicht mehr gewählt werden. Daher muss ich die erste Methode probieren. Um ehrlich zu sein, bin ich ein ziemlicher Neuling, lerne aber recht schnell. Die Sache mit dem Pool ist ja auch nicht wirklich schwer. Ich schreibe nochmal, sobald ich es probiert hab.
BlackJack

@qEagleStrikerp: Wie kommen denn diese Gegenzahlen zustande? Könntest Du nicht erst die Paare bilden und dann zufällig eines der Paare auswählen? Beschreib doch mal das *eigentliche* Problem genauer.
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

BlackJack hat geschrieben:@qEagleStrikerp: Wie kommen denn diese Gegenzahlen zustande? Könntest Du nicht erst die Paare bilden und dann zufällig eines der Paare auswählen? Beschreib doch mal das *eigentliche* Problem genauer.
Theoretisch ginge das mit den Paaren sogar. Aber da gäbe es bei der Benennung wiederum Umstände. Dann müsste ich immer sagen, wenn etwas auf a(x) zutrifft, gilt das auch für b(x). [In x wird eine Zahl von 1-6 eingesetzt]. Da ich mich nicht weiß, wie man soetwas definiert (also eine Variable für die Variable hernimmt), ist mir das zu umständlich. Deine Idee mit dem Pool funktioniert jedenfalls. Danke!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Irgend wie habe ich das Problem immer noch nicht verstanden :K

Wenn irgend etwas zusammengehört, gehört es idR. auch in *eine* Datenstruktur! Wenn Du also Paare von Werten hast, könntest Du z.B. eine Liste von Tupeln bilden und auf dieser dann tatsächlich mit ``random.sample`` arbeiten:

Code: Alles auswählen

pairs = [(1, 2), (2, 4), (1, 5)]

import random

random.sample(pairs, 2)
> [(2, 4), (1, 2)]
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

Hyperion hat geschrieben:Irgend wie habe ich das Problem immer noch nicht verstanden :K

Wenn irgend etwas zusammengehört, gehört es idR. auch in *eine* Datenstruktur! Wenn Du also Paare von Werten hast, könntest Du z.B. eine Liste von Tupeln bilden und auf dieser dann tatsächlich mit ``random.sample`` arbeiten:

Code: Alles auswählen

pairs = [(1, 2), (2, 4), (1, 5)]

import random

random.sample(pairs, 2)
> [(2, 4), (1, 2)]
ie man soetwas definiert (also eine Variable für die Variable hernimmt), ist mir das zu umständlich. Deine Idee mit dem Pool funktioniert jedenfalls. Danke![/quote]

Kurz zu dem Problem. Ich spiele Pokemon schon seit ich klein bin. Und, falls du es kennst, man kann die Viecher züchten. Das ist wichtig, denn die haben versteckte Werte, die man aber ausrechnen kann. Jeder Wert lässt sich prinzipiell verändern, außer dem verstecken. Daher hat man die stärksten Pokemon, wenn alle versteckten Werte ihren Maximalwert 31 haben. Die Wahrscheinlichkeit dafür ist endlos klein. Aber man kann einen Wert leicht auf 31 bekommen (Chance 1:31). Dann züchtet man ihn weiter. Und so versucht man, alle 6 (meistens reichen schon 5) Werte auf 31 zu bringen. Beim Züchten werden hierbei i.d.R 3 Werte von den beiden Elternteilen vererbt. Da beide Eltern je 6 Werte haben, wird also zu Beginn aus 12 Werten zufällig ausgewählt. Das ist dann der 1. vererbte Wert. Dann wird der Gegenwert aussortiert (Sprich, wenn Wert 5 der Mutter vererbt wird, kann nicht auf Wert 5 des Vaters vererbt werden). Der 2. Wert wird nun nur noch aus 10 gewählt. Der 3. dann nur noch aus 8. Da das Pokemon-Baby aber 6 Werte haben soll, müssen die restlichen 3 zufällig generiert werden.

Nun, ich habe das ganze schon auf Papier ausgerechnet. Aber weil ich nie 100%ig sicher bin, ob meine Rechnungen stimmen und ich mal wieder Lust auf Python hatte, will ich mir nun dieses Programm schreiben. Ich bin um ehrlich zu sein sogar schon fertig, war ja kein großer Aufwand. Da es für mich halt ohne Paare leichter war, habe ich lieber so gearbeitet.

PS: Wenn du das Problem anhand meiner Erklärung nicht verstehst, siehe unter "http://pokewiki.de/DV"
BlackJack

@qEagleStrikerp: Da würde ich ein Sample von drei Werten zwischen 0 und 5 (inklusive erstellen) um zu entscheiden welche Werte vererbt werden und dann die Zahlen 0 bis 5 durchgehen. Wenn die aktuelle Zahl im Sample enthalten ist wird zufällig Mama oder Papa ausgewählt und der Wert von dort genommen, ansonsten wird ein Zufallswert erzeugt. Dann entspricht der Quelltext auch von der Struktur her eher dem Vorgehen das Du beschrieben hast.

Edit (ungetestet):

Code: Alles auswählen

import random


def breed(parents):
    to_inherit = set(random.sample(xrange(6), 3))
    return [
        random.choice(parents)[i] if i in to_inherit else random.randint(0, 31)
        for i in xrange(6)
    ]
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

BlackJack hat geschrieben:@qEagleStrikerp: Da würde ich ein Sample von drei Werten zwischen 0 und 5 (inklusive erstellen) um zu entscheiden welche Werte vererbt werden und dann die Zahlen 0 bis 5 durchgehen. Wenn die aktuelle Zahl im Sample enthalten ist wird zufällig Mama oder Papa ausgewählt und der Wert von dort genommen, ansonsten wird ein Zufallswert erzeugt. Dann entspricht der Quelltext auch von der Struktur her eher dem Vorgehen das Du beschrieben hast.

Edit (ungetestet):

Code: Alles auswählen

import random


def breed(parents):
    to_inherit = set(random.sample(xrange(6), 3))
    return [
        random.choice(parents)[i] if i in to_inherit else random.randint(0, 31)
        for i in xrange(6)
    ]
Hmm, das würde vermutlich auch gehen. Ich kämpfe mich im Moment mit meiner Variation rum, allerdings liegt das Problem eher am Zählen der Ergebnisse. Falls ich überhaupt nicht mehr weiterkomme, kann ich ja deine probieren.
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

@BlackJack: Ich habe mein Programm auf deine Variation umgestellt, da ich nicht mehr weitergekommen bin. Allerdings hat auch das mein Problem nicht gelöst. Das Problem selbst besteht nämlich darin, dass ich völlig normale Ergebnisse erhalte, wenn ich das Programm genau einmal durchlaufen lasse. Sobald ich das ganze allerdings in eine Schleife packe, bekomme ich fast nur gleiche Ergebnisse, manche Werte (z.B. der 3. Wert) bleiben sogar bei jedem Durchlauf gleich, unabhängig davon, wie oft ich es probiere. Kennt jemand dieses Problem?
BlackJack

@qEagleStrikerp: Du rufst nicht zufällig `random.seed()` auf? Ansonsten müsstest Du schon ein wenig Code zeigen der das Problem veranschaulicht.
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

BlackJack hat geschrieben:@qEagleStrikerp: Du rufst nicht zufällig `random.seed()` auf? Ansonsten müsstest Du schon ein wenig Code zeigen der das Problem veranschaulicht.
Nein, tue ich nicht. Mein Informatiklehrer gab mir den Tipp, die Systemuhr mit einzubinden, damit die Werte neu generiert werden. Der Code:

Code: Alles auswählen

# -*- coding: cp1252 -*-

# Zufallsgenerator
import random

# Feste Variablen
a1 = 0
a2 = 0
a3 = 31
a4 = 0
a5 = 31
a6 = 31
b1 = 0
b2 = 0
b3 = 31
b4 = 0
b5 = 0
b6 = 0
gesamtzahl = 0
schleife = 3

while schleife != 0:
    # Schleife
    schleife = schleife - 1

    # Vererbte Werte
    c1 = random.randint(1,6)

    pool = set(range(1,7))
    chosen = set([c1])

    c2 = random.choice(list(pool - chosen))
    chosen.add(c2)

    c3 = random.choice(list(pool - chosen))

    # Zuweiseung der vererbten Werte
    if c1 == 1:
        z1 = random.choice([a1,b1])
    elif c1 == 2:
        z2 = random.choice([a2,b2])
    elif c1 == 3:
        z3 = random.choice([a3,b3])
    elif c1 == 4:
        z4 = random.choice([a4,b4])
    elif c1 == 5:
        z5 = random.choice([a5,b4])
    elif c1 == 6:
        z6 = random.choice([a6,b6])

    if c2 == 1:
        z1 = random.choice([a1,b1])
    elif c2 == 2:
        z2 = random.choice([a2,b2])
    elif c2 == 3:
        z3 = random.choice([a3,b3])
    elif c2 == 4:
        z4 = random.choice([a4,b4])
    elif c2 == 5:
        z5 = random.choice([a5,b5])
    elif c2 == 6:
        z6 = random.choice([a6,b5])

    if c3 == 1:
        z1 = random.choice([a1,b1])
    elif c3 == 2:
        z2 = random.choice([a2,b2])
    elif c3 == 3:
        z3 = random.choice([a3,b3])
    elif c3 == 4:
        z4 = random.choice([a4,b4])
    elif c3 == 5:
        z5 = random.choice([a5,b5])
    elif c3 == 6:
        z6 = random.choice([a6,b6])

    # Zufällige Werte
    try:
        test = z1 + 1
    except:
        z1 = random.randint(0,31)

    try:
        test = z2 + 1
    except:
        z2 = random.randint(0,31)

    try:
        test = z3 + 1
    except:
        z3 = random.randint(0,31)

    try:
        test = z4 + 1
    except:
        z4 = random.randint(0,31)

    try:
        test = z5 + 1
    except:
        z5 = random.randint(0,31)

    try:
        test = z6 + 1
    except:
        z6 = random.randint(0,31)

    # Ausgabe
    print(z1)
    print(z2)
    print(z3)
    print(z4)
    print(z5)
    print(z6)
    print("")
Zuletzt geändert von Anonymous am Mittwoch 17. September 2014, 17:41, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@qEagleStrikerp: Vergiss die Systemuhr. Und das da ist mir zu umständlich um es nachzuvollziehen. Nummerierte Namen sind fast immer ein Zeichen dafür das man eigentlich eine Datenstruktur verwenden möchte. Meistens eine Liste. Dann besteht der Quelltext auch nicht aus lauter Quelltextblöcken die durch kopieren und einfügen entstanden sind.
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

BlackJack hat geschrieben:@qEagleStrikerp: Vergiss die Systemuhr. Und das da ist mir zu umständlich um es nachzuvollziehen. Nummerierte Namen sind fast immer ein Zeichen dafür das man eigentlich eine Datenstruktur verwenden möchte. Meistens eine Liste. Dann besteht der Quelltext auch nicht aus lauter Quelltextblöcken die durch kopieren und einfügen entstanden sind.
Okay. Wie funktioniert das mit den Datenstrukturen? Kannst du mir da vielleicht eine gute Anleitung verlinken?

Danke!
BlackJack

@qEagleStrikerp: Im Grunde jedes Grundlagentutorial. Zum Beispiel das in der Python-Dokumentation.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Da du immer paare von `a` und `b` benutzt bietet sich beispielsweise eine Liste von Tupeln an:

Code: Alles auswählen

#Statt a1...a6 und b1...b6
pairs = [(0, 0), # a1, b1
 ....
]
# statt z1 ... z6
zs = [random.choice(pair) for pair in pairs]
Deine `while`-Schleife will eigentlich auch eine `for`-Schleife sein:

Code: Alles auswählen

for _ in range(3):
    ...
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

BlackJack hat geschrieben:@qEagleStrikerp: Im Grunde jedes Grundlagentutorial. Zum Beispiel das in der Python-Dokumentation.
Okay, wenn das so ist, kann es durchaus etwas dauern, bis ich hier nochmal was reinschreiben kann. Darf ich dich per PN benachrichtigen, wenn ich es habe?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

qEagleStrikerp hat geschrieben:Darf ich dich per PN benachrichtigen, wenn ich es habe?
Magst Du uns denn nicht teilhaben an Deinen Ideen oder Fragen? :K
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

Hyperion hat geschrieben:Magst Du uns denn nicht teilhaben an Deinen Ideen oder Fragen? :K
Nun ja, gerne, aber da ich ja erstmal ein wenig in den Dokumentationen und meinem Buch für Python rumstöbern muss, denke ich nicht, dass ihr mir dabei viel helfen könnt ^^
qEagleStrikerp
User
Beiträge: 21
Registriert: Sonntag 14. September 2014, 09:42

@cofi: Wie funktioniert das mit "statt z1-z6"? Wird dabei für jedes Paar der Wert errechnet und dann alle 6 Werte in "zs" eingetragen?
Antworten