Heim  >  Artikel  >  Backend-Entwicklung  >  Bringen Sie Ihnen einen Trick bei, wie Sie mit Python das Endspiel von Landlords lösen können

Bringen Sie Ihnen einen Trick bei, wie Sie mit Python das Endspiel von Landlords lösen können

零下一度
零下一度Original
2017-07-02 10:47:212864Durchsuche

Doudizhu dürfte jedem bekannt sein. Der Artikel stellt vor allem die relevanten Informationen zur Verwendung von Python zum Knacken des Endspiels von Doudizhu vor und ist für jeden von gewisser Bedeutung . Der Referenz-Lernwert, Freunde, die ihn brauchen, können einen Blick unten werfen.

Vorwort

Ich glaube, jeder hat schon einmal Landlords gespielt, daher werde ich die Regeln nicht mehr vorstellen.

Gehe direkt zum Endspielbild, das im Freundeskreis gesehen wurde:

Ich habe diese Frage ausprobiert, als ich sie zum ersten Mal gesehen habe Versuchen Sie, es manuell zu knacken, und jedes Mal, wenn ich glaube, die Erfolgsstrategie des Bauern gefunden zu haben, muss ich feststellen, dass der Bauer nicht entkommen kann. Da das manuelle Knacken nicht alle Möglichkeiten ausschöpfen kann, können wir nur Codes verwenden, die uns bei der Lösung dieses Problems helfen.

In diesem Artikel wird kurz beschrieben, wie solche Probleme durch Code gelöst werden können. Am Ende wird das Endergebnis des Endspiels bekannt gegeben und der Code wird als Open Source bereitgestellt, über den sich jeder beschweren kann.

Minimax

Die Kernidee des Codes ist Minimax. Minimax kann in zwei Teile unterteilt werden: Mini und Max, was jeweils Minimum und Maximum bedeutet.

Was ist das intuitive Verständnis? Es ist ein bisschen so, als würden zwei Leute A und B Schach spielen. A kann nun an N Punkten Schach ziehen, so dass die Brettbewertung des Zuges von A am höchsten ist, aber wenn B an der Reihe ist, wird er sich definitiv in die entsprechende Richtung bewegen am ungünstigsten für A. Gehe, sodass der nächste Schritt von A der von B festgelegten Flugbahn folgen muss und nicht die höchste Brettpunktzahl erreichen kann, die A bei diesem Schritt im ersten Schritt geschätzt hat.

Das Gleiche gilt für das Kartenspiel, wenn der Vermieter die Kartenhand nicht gewinnen kann, egal wie er damit umgeht, dann kann man sagen, dass der Bauer ansonsten eine Gewinnstrategie hat. Der Bauer wird verlieren.

Kernlogik

Wir können eine Funktionhand_out verwenden, um den Kartenspielvorgang einer Person zu simulieren. Wenn jemand im wirklichen Leben Karten spielen möchte, muss er alle Karten in seiner Hand kennen: me_pokers, und er muss auch die Karten kennen, die in der vorherigen Hand gespielt wurden: last_hand. Wenn wir mit dieser Funktion das Spiel zweier Personen simulieren wollen, müssen wir auch alle aktuellen Karten des Gegners kennen: feind_pokers.

Der Rückgabewert dieser Funktion ist, ob ich die Karte gewinnen kann, wenn ich bei me_pokers an der Reihe bin. Gibt true zurück, wenn es gewinnen kann, andernfalls false.


def hand_out(me_pokers, enemy_pokers, last_hand)

Angenommen, wenn ich an der Reihe bin und alle Karten in meiner Hand ausgespielt sind, weiß ich sofort, dass ich gewonnen habe , wenn die Karten des Gegners alles erledigt sind, ich aber nicht, dann habe ich versagt.


if not me_pokers:
 return True
if not enemy_pokers:
 return False

Da ich jetzt an der Reihe bin, Karten zu spielen, muss ich zunächst alle Kartenkombinationen kennen, die ich jetzt spielen kann. Hinweis: Diese Kombination beinhaltet die Strategie des Prüfens (d. h. Nichtspielens).


all_hands = get_all_hands(me_pokers)

Jetzt wollen wir alle möglichen Handkombinationen durchlaufen.

Zuerst muss ich wissen, welche Karte der Gegner in der letzten Hand gespielt hat.

  • Wenn der Gegner sich entschieden hat, in der vorherigen Hand zu checken, oder die vorherige Hand nicht hatte, dann darf ich in dieser Runde nicht checken, aber ich kann jede Karte spielen

  • Wenn mein Gegner in der vorherigen Hand eine Karte gespielt hat, muss ich in dieser Runde eine größere Karte spielen oder mich dafür entscheiden, direkt zu checken (ohne eine Karte auszuspielen)

Hier kommt der entscheidende Punkt: Nachdem wir meine Karten gespielt oder uns entschieden haben, zu passen, müssen wir einen rekursiven Aufruf verwenden, um das nächste Verhalten des Gegners zu simulieren. Wenn das nächste Kartenspiel des Gegners nicht gewinnen kann, wird mein Kartenspiel dieses Mal definitiv gewinnen; andernfalls verliere ich bei jeder Kartenspielauswahl, die ich treffe.

Der gesamte Code lautet wie folgt:


def hand_out(me_pokers, enemy_pokers, last_hand, cache):
 if not me_pokers:
  # 我全部过牌,直接获胜
  return True
 if not enemy_pokers:
  # 对手全部过牌,我失败
  return False
 # 获取我当前可以出的所有手牌组合,包括过牌
 all_hands = get_all_hands(me_pokers)
 # 遍历我的所有出牌组合,进行模拟出牌
 for hand in all_hands:
  # 如果上一轮对手出了牌,则这一轮我必须要出比对手更大的牌 或者 对手上一轮选择过牌,那么我只需出任意牌,但是不能过牌
  if (last_hand and can_comb2_beat_comb1(last_hand, hand)) or (not last_hand and hand['type'] != COMB_TYPE.PASS):
   # 模拟对手出牌,如果对手不能取胜,则我必胜
   if not hand_out(enemy_pokers, make_hand(me_pokers, hand), hand, cache):
    return True
  # 如果上一轮对手出了牌,但我这一轮选择过牌
  elif last_hand and hand['type'] == COMB_TYPE.PASS:
   # 模拟对手出牌,如果对手不能取胜,则我必胜
   if not hand_out(enemy_pokers, me_pokers, None, cache):
    return True
 # 如果之前的所有出牌组合均不能必胜,则我必败
 return False

Erstellen Sie die obige Kernlogik von

Sobald Sie das herausgefunden haben, wird der Bau eines Crackers ganz einfach.

Zunächst müssen wir Zahlen verwenden, um die Größe der Karten darzustellen. Hier verwenden wir 3 für 3, 11 für J, 12 für Q und so weiter...

Zweitens müssen wir herausfinden, dass für alle Kartenkombinationen in einer Hand die Funktion get_all_hands erforderlich ist. Die konkrete Implementierung ist kompliziert, aber sehr einfach, daher werde ich hier nicht auf Details eingehen.

Dann benötigen wir auch eine Funktion zur Beurteilung der Kartenstärke can_comb2_beat_comb1(comb1, comb2) . Diese Funktion wird verwendet, um die Kartenstärke der beiden Handgruppen zu vergleichen, um zu sehen, ob Kamm2 Kamm1 besiegen kann. Das Einzige, was Sie beachten müssen, ist, dass in den Regeln von Landlord, mit Ausnahme von Bomben, alle anderen Karten gleich stark sind. Es können nur Karten des gleichen Typs verglichen werden.

Schließlich benötigen wir eine simulierte Kartenspielfunktion make_hand(pokers, hand) , die dazu dient, die verbleibenden Hände nach dem Spielen einer Hand mit Poker in der Hand herauszufinden. Die Implementierung ist ebenfalls sehr einfach, einfach die Karten entfernen wurden gespielt.

Effizienz

Aufgrund der großen Anzahl möglicher Hände in einem Kartenspiel ist die Anzahl der rekursiven Zweige riesig. Daher ist der Zeitaufwand sehr groß, was der Faktorebene O(N!) entspricht. Nach Stirlings Formel beträgt er ungefähr O(N^N).

Da es möglicherweise viele doppelte Karten gibt, führt dies zu vielen wiederholten rekursiven Aufrufen. Das Hinzufügen eines Cache kann also die Effizienz erheblich verbessern.

ist die Beschreibung unserer Hand, der Hand des Gegners und der Hand der vorherigen Runde. (str(me_pokers)+str(enemy_pokers)+str(last_hand)) ist der Schlüssel, und das Ergebnis wird im Cache-Wörterbuch gespeichert. Wenn Sie das nächste Mal auf dieselbe Situation stoßen, können Sie sie direkt aus dem Cache-Wörterbuch abrufen, ohne die Berechnung erneut wiederholen zu müssen. Die Zeitkomplexität wird auf exponentielles O(C^N) optimiert.

Ergebnis

Das Ergebnis der Codeberechnung ist, dass Landwirte keine Gewinnstrategie haben. Mit anderen Worten: Solange die Grundbesitzer wissen, wie man spielt, können die Bauern nicht gewinnen. Ist die Klassenverfestigung schon so...

Open Source

Der Code ist auf Github platziert: doudizhu_solver, oder Sie können ihn lokal unter der MIT-Lizenz herunterladen , und spielen Sie, wie Sie möchten.

Das obige ist der detaillierte Inhalt vonBringen Sie Ihnen einen Trick bei, wie Sie mit Python das Endspiel von Landlords lösen können. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn