[PYTHON] Diskriminierung der Agari-Form von Mahjong

Diskriminierung der Agari-Form von Mahjong

Es scheint, dass die Wahrscheinlichkeit von Tenwa einmal in 330.000 Mal ist Ich wollte es versuchen, also schrieb ich es in Python, Das war nerviger als ich erwartet hatte.

Der Algorithmus ist hier. http://www.onionsoft.net/hsp/mahjong.txt

Die Rolle oder das Warten ist in Ordnung ... Wenn es mir gut geht ~~ Ich schreibe es das nächste Mal ~~.

Ich habe es geschrieben @ [25.09.2014] http://qiita.com/arc279/items/1a7853ad8e2dc35961d1

Bestätigter Vorgang mit python2.7.6.

Die Grundlagen

Ich habe es ehrlich geschrieben. Ich habe list von builtin geerbt, weil es problematisch ist, aber ich denke, dass es besser ist, es zu delegieren.

Das Waschen wird auf zufällig geworfen.

mj.py


#!/usr/bin/env python
# -*- coding: utf8 -*-

import itertools
import random
from collections import OrderedDict

class Yama(list):
    u'''Wand'''
    WANPAI_NUM = 14

    class TsumoDoesNotRemain(Exception):
        u'''Nur der König ist noch übrig'''
        pass

    def __init__(self):
        pais = [ Pai.from_index(i) 
                for i in range(Pai.TOTAL_KIND_NUM * Pai.NUM_OF_EACH_KIND) ]
        #Waschen
        random.shuffle(pais)
        super(Yama, self).__init__(pais)

    def tsumo(self):
        u'''Eigenständigkeit'''
        if len(self) <= self.WANPAI_NUM:
            raise self.TsumoDoesNotRemain

        return self.pop(0)

    def wanpai(self):
        return self[-self.WANPAI_NUM:]

    def haipai(self):
        u'''Verteilung'''
        tehais = [ Tehai(), Tehai(), Tehai(), Tehai() ] #Osten(Elternteil)Südwesten Nord

        # 4*3 Runden
        for j in range(0, 3):
            for tehai in tehais:
                for i in range(0, 4):
                    pai = self.tsumo()
                    tehai.append(pai)

        #Choncho
        for tehai in tehais:
            pai = self.tsumo()
            tehai.append(pai)

        pai = self.tsumo()
        tehais[0].append(pai)

        return tehais

class Pai(object):
    u'''牌'''

    TOTAL_KIND_NUM = 34          # M/P/S +Alle Arten von Zeichen
    NUM_OF_EACH_KIND = 4         #4 Blatt pro Typ
    NUM_OF_EACH_NUMBER_PAIS = 9  # M/P/Die Anzahl von S ist 1..Bis zu 9

    class Suit:
        M = 0   #Mann
        P = 1   #Tube
        S = 2   #Messen
        J = 3   #Charakter

        NAMES = {
            M: u"Mann",
            P: u"Tube",
            S: u"Messen",
            J: u" ",
        }

    class Num:
        NAMES = {
            1: u"einer",
            2: u"zwei",
            3: u"drei",
            4: u"vier",
            5: u"Fünf",
            6: u"Sechs",
            7: u"Sieben",
            8: u"Acht",
            9: u"Neun",
        }

    class Jihai:
        E   = 1
        S   = 2
        W   = 3
        N   = 4
        HAK = 5
        HAT = 6
        CHU = 7

        NAMES = {
            E:   u"Osten",
            S:   u"Süden",
            W:   u"Westen",
            N:   u"Norden",
            HAK: u"Weiß",
            HAT: u"Abwehrmittel",
            CHU: u"Während ~",
        }

    @classmethod
    def yaochupai(cls):
        u'''么 9 牌'''
        return [
            cls(cls.Suit.M, 1),
            cls(cls.Suit.M, 9),
            cls(cls.Suit.P, 1),
            cls(cls.Suit.P, 9),
            cls(cls.Suit.S, 1),
            cls(cls.Suit.S, 9),
            cls(cls.Suit.J, cls.Jihai.E),
            cls(cls.Suit.J, cls.Jihai.S),
            cls(cls.Suit.J, cls.Jihai.W),
            cls(cls.Suit.J, cls.Jihai.N),
            cls(cls.Suit.J, cls.Jihai.HAK),
            cls(cls.Suit.J, cls.Jihai.HAT),
            cls(cls.Suit.J, cls.Jihai.CHU),
        ]

    def __init__(self, suit, num):
        self.suit = suit
        self.num  = num

    @property
    def index(self):
        return self.suit * self.NUM_OF_EACH_NUMBER_PAIS + self.num

    def __repr__(self):
        #return str((self.suit, self.num))    #Taple-Anzeige
        if self.suit == Pai.Suit.J:
            return Pai.Jihai.NAMES[self.num].encode('utf-8')
        else:
            return (Pai.Num.NAMES[self.num] + Pai.Suit.NAMES[self.suit]).encode('utf-8')

    def __eq__(self, other):
        return self.suit == other.suit and self.num == other.num

    @classmethod
    def from_index(cls, index):
        kind = index % cls.TOTAL_KIND_NUM

        if True:
            suit = kind / cls.NUM_OF_EACH_NUMBER_PAIS
            num  = kind % cls.NUM_OF_EACH_NUMBER_PAIS + 1
        else:
            if 0 <= kind < 9:
                suit = cls.Suit.M
                num  = kind - 0 + 1
            elif 9 <= kind < 18:
                suit = cls.Suit.P
                num  = kind - 9 + 1
            elif 18 <= kind < 27:
                suit = cls.Suit.S
                num  = kind - 18 + 1
            elif 27 <= kind < 34:
                suit = cls.Suit.J
                num  = kind - 27 + 1

        assert(cls.Suit.M <= suit <= cls.Suit.J)
        assert(1 <= num <= cls.NUM_OF_EACH_NUMBER_PAIS)

        return cls(suit, num)

class Tehai(list):
    u'''Handwerk'''

    @staticmethod
    def sorter(a, b):
        u'''Wie macht man'''
        return a.suit - b.suit if a.suit != b.suit else a.num - b.num

    def rihai(self):
        u'''Rimu'''
        self.sort(cmp=self.sorter)
        return self

    def aggregate(self):
        u'''{牌 Samen:Anzahl der Blätter}Aggregat in Form von'''
        hash = { x[0]: len(list(x[1])) for x in itertools.groupby(self.rihai()) }
        ret = OrderedDict()
        #Schlüsselkacheln bleiben jetzt sortiert
        for x in sorted(hash.keys(), cmp=self.sorter):
            ret[x] = hash[x]
        return ret

    def show(self):
        u'''Anzeige in leicht lesbarer Form'''
        line1 = u"|"
        line2 = u"|"
        for pai in self.rihai():
            if pai.suit != Pai.Suit.J:
                line1 += Pai.Num.NAMES[pai.num] + u"|"
                line2 += Pai.Suit.NAMES[pai.suit] + u"|"
            else:
                line1 += Pai.Jihai.NAMES[pai.num] + u"|"
                line2 += u" |"

        print line1.encode("utf-8")
        print line2.encode("utf-8")

Agari Typprüfung

Gibt es sieben Kinderpaare und Kokushi Musou? Dieser Bereich hängt von der Interpretation ab, also ist es gut. Hier schrieb ich, dass die sieben Paare keinen Spatzenkopf hatten und der Kokushi Musou zwei Spatzenköpfe hatte.

Es war mühsam, den Urteilsteil für die Klasse auszuschneiden, also benutzte ich einen Verschluss.

mj.py


def check_hohra(tehai):
    u'''Überprüfen Sie die Form des Endes'''
    assert(len(tehai) == 14)
    pais = tehai.aggregate()
    keys = pais.keys()
    length = len(keys)
    #print pais, keys, length

    def check_chitoitsu(pais):
        u'''Sieben Paare prüfen'''
        if all([ num == 2 for pai, num in pais.items()]):
            return (), [ (pai, pai) for pai, num in pais.items() ]
        return None

    def check_kokushimusou(pais):
        u'''Kokushi Musou Check'''
        if length != 13:
            return None

        yaochupai = Pai.yaochupai()
        mentsu = []
        for pai, num in pais.items():
            if pai not in yaochupai:
                return None

            # TODO:Ist es in Ordnung, zwei von ihnen hier zu haben?
            if num == 2:
                atama = (pai, pai)
            else:
                assert(num == 1)
                mentsu.append(pai)

        return atama, mentsu


    def search_syuntu(pais):
        u'''Finde Junko'''
        for i in range(length):
            if pais[keys[i]] >= 1:
                first = keys[i]
                try:
                    second = keys[i+1]
                    third  = keys[i+2]
                except IndexError as e:
                    #Es gibt keine verbleibenden 2 Typen
                    continue

                if first.suit == Pai.Suit.J:
                    #Charaktere können nicht Junko sein
                    continue

                if not (first.suit == second.suit and first.suit == third.suit):
                    #Verschiedene Typen
                    continue

                if not ((second.num == first.num+1) and (third.num == first.num+2)):
                    #Keine Seriennummer
                    continue

                if pais[second] >= 1 and pais[third] >= 1:
                    pais[first]  -= 1
                    pais[second] -= 1
                    pais[third]  -= 1
                    return (first, second, third)

        return None

    def search_kohtu(pais):
        u'''Finde die Gravur'''
        for j in range(length):
            if pais[keys[j]] >= 3:
                pais[keys[j]] -= 3
                return (keys[j], keys[j], keys[j])

        return None

    #Sieben Paare
    tmp = pais.copy()
    ret = check_chitoitsu(tmp)
    if ret:
        return [ ret ]

    #Kokushi Musou
    tmp = pais.copy()
    ret = check_kokushimusou(tmp)
    if ret:
        return [ ret ]

    #Grundform
    candidate = []
    for i in range(length):
        #Finde den Kopf
        if not (pais[keys[i]] >= 2):
            continue

        tmp = pais.copy()
        atama = (keys[i], keys[i])
        tmp[keys[i]] -= 2

        mentsu = []
        while True:
            #print tmp
            ret = search_syuntu(tmp) or search_kohtu(tmp)
            if ret is None:
                ret = search_kohtu(tmp) or search_syuntu(tmp)
                if ret is None:
                    #Ich kann weder Junko noch Kiko machen
                    break
            mentsu.append(ret)

        #print atama, mentsu, tmp
        if len(mentsu) == 4:
            #4 Gesicht 1 Spatzenkopfform
            candidate.append( (atama, mentsu) )

    return candidate

Scheck von Tenwa

Es wäre schön, wenn es nach dem Arrangement der Eltern wie ein Agari geformt wäre, also wäre es so.

mj.py



def check_tenho():
    for cnt in (x for x in itertools.count()):
        yama = Yama()
        oya, _, _, _ = yama.haipai()
        ret = check_hohra(oya)
        if ret:
            print cnt
            oya.show()
            for atama, mentsu in ret:
                print atama, mentsu
            break

if __name__ == '__main__':
    #Versuchen Sie es ungefähr 100 Mal
    for x in range(100):
        check_tenho()

Und das Ergebnis ist

Wenn es auch nach 600.000 Versuchen nicht herauskommt, kommt es nicht heraus, und wenn es herauskommt, kommt es ungefähr 20.000 Mal heraus.

Immer noch 20.000 Mal ... oder __ Wenn Sie nicht denken __ Vielleicht ist etwas gelähmt.

Nun, wenn die Anzahl der Versuche zunimmt, denke ich, dass sie sich nach dem Gesetz der großen Anzahl auf 330.000 Mal niederschlagen wird. vielleicht. Es dauert lange und ist nervig, deshalb habe ich es nur ungefähr 10 Mal versucht. Ich war zufrieden, als ich es schrieb.

Wenn Sie zwischen Rollen und Warten unterscheiden möchten, müssen Sie es wahrscheinlich neu schreiben ...

Bonus

Das zum Debuggen.

mj.py


    class Debug:
        u'''for debug'''

        TEST_TEHAIS = [
            [2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7],
            [0, 0, 8, 8, 13, 13, 20, 20, 25, 25, 29, 29, 31, 31],      #Wann
            [0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33, 9],      #Quietschend
            [33, 33, 33, 32, 32, 32, 31, 31, 31, 0, 0, 0, 2, 2],    #Daisangen
            [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 1],      #Churenpoto
            [19, 19, 20, 20, 21, 21, 23, 23, 23, 25, 25, 32, 32, 32],      #Ryu-so
            [0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 0, 1, 2],      #Chinitsu Ittsu Epaco
        ]

        @classmethod
        def tehai_from_indexes(cls, indexes):
            assert(len(indexes) == 13 or len(indexes) == 14)
            return Tehai([ Pai.from_index(x) for x in indexes ])

        @classmethod
        def test_tehai(cls, idx = None):
            if not idx:
                #14 selbst gemacht
                yama = Yama()
                return Tehai([ yama.tsumo() for x in range(14) ])
            else:
                return cls.tehai_from_indexes(cls.TEST_TEHAIS[idx])

Wenn Sie interessiert sind

Probieren Sie es mit Ihren eigenen Händen aus!

Recommended Posts

Diskriminierung der Agari-Form von Mahjong
Die Form der eindimensionalen Anordnung von Numpy war kompliziert
Beurteilung des Endes von Mahjong durch Kombinationsoptimierung
Der Beginn von cif2cell
Die Bedeutung des Selbst
der Zen von Python
Die Geschichte von sys.path.append ()
[Anmerkung] Inhalt der Form [0], Form [1], Form [2]
Erzeugen Sie diese Form des Bodens einer Haustierflasche
Tensor verstehen (2): Form
Rache der Typen: Rache der Typen
Richten Sie die Version von chromedriver_binary aus
Scraping das Ergebnis von "Schedule-Kun"
10. Zählen der Anzahl der Zeilen
Die Geschichte des Baus von Zabbix 4.4
Diskriminierung der Mahjong-Warteform
Auf dem Weg zum Ruhestand von Python2
Vergleichen Sie die Schriftarten von Jupyter-Themen
Holen Sie sich die Anzahl der Ziffern
Erläutern Sie den Code von Tensorflow_in_ROS
Verwenden Sie die Clustering-Ergebnisse erneut
GoPiGo3 des alten Mannes
Berechnen Sie die Anzahl der Änderungen
Ändern Sie das Thema von Jupyter
Die Popularität von Programmiersprachen
Ändern Sie den Stil von matplotlib
Visualisieren Sie die Flugbahn von Hayabusa 2
Über die Komponenten von Luigi
Verknüpfte Komponenten des Diagramms
Filtern Sie die Ausgabe von tracemalloc
Über die Funktionen von Python
Simulation des Inhalts der Brieftasche
Die Kraft der Pandas: Python