Die von Prolog inspirierte kommerzielle Lösung ist seit über 10 Jahren in Betrieb

Für die meisten Programmierer, die sogar von Prolog gehört haben, ist dies nur ein seltsames Artefakt aus einer Zeit, als Computer die Größe von Dinosauriern hatten. Einige haben am Institut bestanden und vergessen. Und nur Spezialisten, schmal wie ein Blatt A4, sind in der modernen Welt auf etwas Ähnliches gestoßen. Es ist einfach so passiert, dass ich 2003 einige Lösungen von Prolog in kommerziellen Flash-Spielen verwendet habe und sie die Franzosen mehr als ein Jahrzehnt lang begeistert haben. Außerdem habe ich diese halbdeklarative Entscheidung nicht angewendet, weil ich Bratkos Buch gelesen habeund war beeindruckt, aber weil unser Projekt es wirklich brauchte. Ich versuche immer noch regelmäßig, diese Lösung auf einem modernen Niveau zu reproduzieren, da sie in einer modernen Spielebranche sehr nützlich wäre, aber leider jedes Mal, wenn wichtigere Dinge zu tun sind ... Im Allgemeinen werde ich Ihnen alles darüber erzählen.





Ein Screenshot desselben Flash-Spiels heißt Sie weiterhin unter toox.com/jeux/jeux-de-cartes/coinche willkommen



Erklärung des Problems und seiner Relevanz



Quosh, Belote und Tarot sind nationale französische Spiele. Gemäß den Regeln entspricht dies in etwa der Spielpräferenz in einem geschlossenen Spiel, und ein Paar wird für ein Paar gespielt. Anhand der Anzahl der Bestechungsgelder und der Trumpfkarte, die Ihr Partner vorschlägt, um das Spiel während des Verhandelns anzukündigen, können Sie ungefähr verstehen, welche Art von Karten er hat. Das Spiel ist lang und die Existenz einer KI, die das Spiel irgendwie beenden kann, ist einfach von entscheidender Bedeutung, da einer der Spieler einfach den Tisch verlassen kann und entscheidet, dass er hoffnungslos verliert, und der Gewinner es natürlich auf das Endergebnis auf der Anzeigetafel bringen möchte. In diesem Fall beendet die KI das Spiel für den verlorenen Spieler. Aber da wir KI haben, können wir das Spiel starten, indem wir den KI-Shki auf leeren Feldern nerven. Also haben wir diese großartigen Spiele der Masse vorgestellt und schnell herausgefunden, dass es grundsätzlich zwei Möglichkeiten gibt, wie die Franzosen gerne spielen.Ungefähr die Hälfte aller Tische wartet darauf, bis zum Sieg mit lebenden Menschen besetzt zu werden, und die Hälfte kommt nach unten und startet das Spiel gegen drei KI, wie im obigen Screenshot.



Da das Spiel geschlossen ist, sind die Leute im Prinzip bereit, Robotern kleinere Fehlkalkulationen und alternative Begabungen zu verzeihen. Hauptsächlich, weil die Karten des Roboters nicht sichtbar sind. "Unter dem Spieler mit Simak", "Unter der Vistuza mit dem Ass" und ähnliche einfache Regeln, die ich von unserem französischen Kunden herausgeschüttelt habe, haben es uns ermöglicht, den minimal akzeptablen Werfer zu machen. Es war in einer Woche direkt am Ifs nafigched. Auf der anderen Seite wird das Spiel "zwei für zwei" gespielt, Punkte werden für ein Paar gezählt, und natürlich möchte der Spieler nicht, dass sein dummer Partner "vom zweiten König" eintritt, dh er hat einen König in der Hand und eine andere kleine Karte, zu der er einen Zug macht diese Farbe, anstatt den Gegner ein Ass spielen zu lassen, es mit einer kleinen Karte passieren zu lassen und den nächsten Zug in dieser Farbe mit seinem König zu machen. (In diesen Spielen ist die zweitälteste Karte 10,aber im Folgenden werde ich in russischen Begriffen sprechen). Aber wenn das Ass aus irgendeinem Grund das Spiel verlassen hat und Sie eine Königin und etwas anderes Kleines haben, dann ist es fast wie beim zweiten König. Vor allem, wenn Sie die Trumpfkarten vorbestellen. Und Sie spielen zum Beispiel nicht Belote, wo 32 Karten verwendet werden, sondern Tarot, bei dem das Spiel mit einem Kartenspiel von 78 Karten gespielt wird (das gleiche, das manche Leute erraten). Und dort kann in einigen Fällen nicht einmal die dritte Königin, sondern der vierte Wagenheber das Bestechungsgeld annehmen. All dies führt im Allgemeinen zu einer solchen Anzahl von Randfällen, dass ein dummer Dummy auf ifs irgendwie völlig inakzeptabel komplex wird. Und an diesem Punkt sagte ich: „Bah! Ich habe viel gelesenZum Beispiel spielen Sie nicht Belote, wo 32 Karten verwendet werden, sondern Tarot, bei dem das Spiel mit einem Kartenspiel von 78 Karten gespielt wird (das gleiche, das manche Leute erraten). Und dort kann in einigen Fällen nicht einmal die dritte Königin, sondern der vierte Wagenheber das Bestechungsgeld annehmen. All dies führt im Allgemeinen zu einer solchen Anzahl von Randfällen, dass ein dummer Dummy auf ifs irgendwie völlig inakzeptabel komplex wird. Und an diesem Punkt sagte ich: „Bah! Ich habe viel gelesenZum Beispiel spielen Sie nicht Belote, wo 32 Karten verwendet werden, sondern Tarot, bei dem das Spiel mit einem Kartenspiel von 78 Karten gespielt wird (das gleiche, das manche Leute erraten). Und dort kann in einigen Fällen nicht einmal die dritte Königin, sondern der vierte Wagenheber das Bestechungsgeld annehmen. All dies führt im Allgemeinen zu einer solchen Anzahl von Randfällen, dass ein dummer Dummy auf ifs irgendwie völlig inakzeptabel komplex wird. Und an diesem Punkt sagte ich: „Bah! Ich habe viel gelesenKurz und beeindruckt! " Dann rannte ich für ein paar Tage aus dem Büro, setzte mich mit einem Laptop in ein Café und brachte ein paar Tage später etwas hervor.



Schlüsselideen



Worauf basiert der Prolog deklarativ? Zu Fakten zum Beispiel:



('', '').
('', '').


und zu Bedingungen oder Regeln, zum Beispiel, wenn A Mutter B ist, dann ist A ein Mädchen:



() :- (, ).


Natürlich verstehe ich, dass in unserer Zeit nicht alles so einfach ist, und im Allgemeinen ist es sogar ein wenig unanständig, dies zu sagen, aber in den Tagen, als die Menschen an formale Logik glaubten, gab es in solchen Beispielen nichts Verwerfliches. Sagen wir für Toleranz:



(A, B) :- (A, B).
(, ) :- (, ), (, ).


Und dann fragst du mich so:



?-  (X, '')


Und der schrecklich logische Prolog antwortet Ihnen:



X = ''
X = ''


Die Idee war, dass der Benutzer seinen Kopf nicht dadurch erwärmte, in welcher Reihenfolge und in welcher Menge das Prologsystem Regeln auf Fakten anwenden würde, um zu einer Antwort zu kommen. Aber so einfach ist das natürlich nicht. Der Prolog ist mit Krücken, funktionalen Ergänzungen, Schneidern verschiedener Argumentationszweige und dergleichen bewachsen und läuft immer noch regelmäßig in unendliche Rekursion davon.



In dem Buch dieses sehr inspirierenden Bratko wurde ein ganzes Kapitel darüber gewidmet, wie die Prologmaschine im Inneren realisiert wird. Kurz gesagt, es geht den Baum aller Regeln eingehend durch und versucht, jede der Regeln der Reihe nach auf die Menge aller ihm bekannten Fakten und Variablen anzuwenden, um einen neuen Status zu erhalten. Wenn die Regel nicht angewendet werden kann, wird zum vorherigen Schritt zurückgesetzt und versucht, eine andere Option zu versuchen.



Wenn Sie es schaffen, etwas Nützliches zusammenzukratzen, nimmt der Computer die Liste der Regeln und beginnt mit dem nächsten Schritt, um nach Regeln zu suchen, die vom Anfang der Liste an angewendet werden sollen. Wenn eine Variable in den Regeln vorkommt, merkt sich die Maschine außerdem, welche Zustände dieser Variablen unter Berücksichtigung der bereits angewendeten Regeln vorliegen können. Dies nennt man Ausarbeiten. Wenn eine Instanziierung der Variablen gefunden werden kann, die die Frage wahr macht, wird diese Instanziierung gedruckt. Dann kann sie nach der nächsten Konkretisierung suchen und so weiter. Im obigen künstlichen Beispiel hat das System zwei Konkretisierungen gefunden, die die Bedingungen erfüllen.



Ich möchte die Spielregeln irgendwie ähnlich formulieren, aber natürlich nicht wörtlich. Mit einer gewissen Erfahrung im Debuggen von Programmen in Prolog war ich überhaupt nicht bestrebt, mich diesem Debuggen und diesen Gemeinkosten für mein Produkt zu stellen.





Erstens sollte dies alles nicht auf einer Reihe verstreuter Fakten funktionieren, sondern auf dem Spielstatusbaum - einem Modell - und die Ergebnisse seiner Arbeit auch auf denselben Baum anwenden. Zweitens möchte ich die Regeln so schreiben, dass sich ein bestimmter Wert, eine Variable und ein arithmetischer Ausdruck an derselben Position befinden können, und das System sollte dies entsprechend behandeln, ohne dem Programmierer zusätzliche Fragen zu stellen und ohne zusätzliche Syntax zu benötigen. Drittens ist es natürlich von entscheidender Bedeutung, die unendliche Rekursion aufzugeben, aber einige Wiederholungen der Anwendung der Regeln sollten noch übrig bleiben. Viertens sollte das Regelsystem in einem sehr bequemen, für Menschen lesbaren Format geschrieben sein, damit auf einen Blick klar ist, was der Autor sagen wollte. Und schließlich, fünftens,All dies muss an ein praktisches Protokollierungs- und Debugging-Tool gebunden sein, damit es einfach ist, den Überlegungen dieses Systems zu folgen und zu verstehen, warum bestimmte Regeln nicht den Erwartungen widersprechen.



Dies ist natürlich kein universeller Prädikatenlogiklöser erster Ordnung, sondern lediglich ein praktisches deklaratives System von Spielregeln. Was im praktischen Sinne auch sehr gut ist. Dafür habe ich mir viel später bei einem der folgenden Projekte den Namen Logrus ausgedacht. Ich werde die endgültige Version sofort beschreiben und alle Zwischenstufen der Motorentwicklung umgehen.



Die resultierende Syntax der Logrus-Bibliothek



Es wird viel Syntax geben.



1) Zur Laufzeit wird der Entscheidungsbaum in Form einiger Klassen gespeichert, aber das erste, was ich ihm anhängte, war Import und Export in JSON, sobald es funktionierte. Es stellte sich heraus, dass dies auch praktisch ist, da Sie die Regeln aus der Datei ohne Neukompilierung aktualisieren können, wenn sich an Ihrer Datenstruktur nicht viel geändert hat. Das Schreiben in Form von JSON erwies sich als so praktisch, dass Programmierer in einem der folgenden Projekte, wenn sie es eilig hatten, manchmal einfach einen normalen Befehl schrieben, dies einfach tatenstate.AplayJSON("...");und darin wurde die erforderliche Aktion als JSON-Zeichenfolge eingefügt. Dies hatte natürlich keine sehr guten Auswirkungen auf die Leistung, aber wenn nicht regelmäßig und nur als Reaktion auf Benutzerklicks, ist es nicht beängstigend ... Den Rest werde ich sofort mit JSON veranschaulichen. Ich reproduziere JSONs ungefähr aus dem Speicher, weil es eine verdammt lange Zeit war. Genau genommen garantiert JSON nicht die Reihenfolge der Knoten im Objekt, aber die meisten Bibliotheken respektieren dies immer noch, und hier und darunter wird die Reihenfolge der Knoten aktiv verwendet.



2) Die Regel wurde zur Hauptstruktureinheit des Motors. Eine Regel besteht aus einer Bedingung und einer Aktion. Normalerweise kamen die Regeln in Arrays und wurden jedes Mal einzeln angewendet:



[{"condition":{}, "action":{}},
 {"condition":{}, "action":{}}]


3) Jede Regel enthält eine Bedingung - dies ist eine Baumvorlage, die möglicherweise Variablen enthält. Das System prüft, ob der Statusbaum mit der Vorlage für Werte der Variablen übereinstimmt. Und wenn es eine solche Konkretisierung findet, wird eine Aktion ausgelöst. Zum Beispiel:



{"condition":{
    "player":{
        "$X":{"gold" : "<20", "name":"$NAME"}
    }},
    "action":{}}


Eine solche Konstruktion bedeutet, dass zum Auslösen einer Aktion im Baum auf der obersten Ebene ein "Spieler" -Knoten vorhanden sein muss, in dem sich ein oder mehrere untergeordnete Knoten befinden, von denen jeder Felder "Gold" mit einem Wert von weniger als 20 und "Name" aufweist. Wenn eine solche Bedingung erfüllt ist, wird die Aktion aufgerufen und als Eingabe in der X-Variablen - dem Schlüssel des Knotens - und in der NAME-Variablen im Namen des Spielers übergeben. Wenn es mehrere geeignete Knoten gibt und dementsprechend mehrere mögliche Instanziierungen, wird die Aktion mehrmals mit jeder der gefundenen Instanziierungen am Eingang aufgerufen.



4) Anfangs war dort alles etwas weniger flexibel, aber dann hat Valyard, den viele aus zahlreichen Gesprächen auf Konferenzen über Unity kennen, uns einen Parser geschraubt, der arithmetische Ausdrücke zu einem schnellen Entscheidungsbaum analysiert, und Flexibilität blühte schließlich in einer gewalttätigen Farbe auf.



5) C $ -Variablennamen beginnen. Sie können als Schlüssel wie $ X angezeigt werden, und dann werden mehrere Instanziierungen ausgewählt, da ein Blattwert wie $ NAME in arithmetische Ausdrücke eingefügt werden kann: Beispiel: {"gold": "<$ X * 10" } Und dann kann es verwendet werden, um die Bedingungen zu überprüfen. Nur diejenigen Spieler, die mehr Gold als ihre Ordnungszahl multipliziert mit 10 haben, bestehen die Prüfung. Schließlich können sie in einem Ausdruck direkt berechnet werden, zum Beispiel: {"gold": "$ X = 3 + $ this "} wobei $ dies der Wert des aktuellen Punktes ist, an dem die Berechnung aufgerufen wurde. Durch Passieren dieses Knotens wird der Wert der Variablen $ X als 3 + die Menge an Gold konkretisiert, die der Spieler hat. Von den MöglichkeitenWas in den Sinn kam, wurde nicht implementiert, es gab nur eine - die Variable kann nicht zuerst auf der rechten Seite eines arithmetischen Ausdrucks erscheinen. Dies ist ein Fehler. Wenn sie als Argument verwendet wird, muss sie bereits auf eine von mehreren anderen Arten konkretisiert werden.



6) Eine Variable in einem Ausdruck kann so oft vorkommen, wie Sie möchten, während die erste Erwähnung dies angibt und die nächste eine Überprüfung auf Gleichheit ist. Zum Beispiel wird eine solche Konstruktion den ersten Spieler nehmen, ihn auf Geld prüfen und dann nach einem anderen Spieler suchen, für den der erste das Ziel wäre. Wenn es es nicht findet, wird es bis zum Punkt der Konkretisierung zurückgesetzt. X wählt den nächsten Spieler aus, sucht nach Geld usw., bis alle möglichen Optionen X und Y durchlaufen sind. Durch Vertauschen der Zeilen ändert der Programmierer die Reihenfolge der Schecks, jedoch nicht das Endergebnis:



{ "player":{
    "$X":{"gold":">20"},
    "$Y":{"target":"$X"}
}}


7) Die Aktion ist auch eine Baumvorlage, die Variablen und arithmetische Ausdrücke enthalten kann, und der Spielstatusbaum wird entsprechend geändert. Zum Beispiel würde diese Vorlage Spieler X einem Gegner in Form von Spieler Y zuweisen, aber wenn aus irgendeinem Grund Spieler Y nicht existierte, würde sie erstellt. Und der "überflüssige" Spieler wird komplett entfernt. Zum Zeitpunkt der Erstellung des Spiels aus dem Screenshot war das Löschzeichen null, aber dann habe ich es durch ein reserviertes Wort ersetzt, falls jemand einen leeren Wert per Schlüssel einfügen muss. Im Allgemeinen ist das Prinzip meiner Meinung nach klar und die Bedeutung der mit dem Spiel ausgeführten Aktionen ist im Grunde dieselbe.



{
    "condition":{
    "player":{
        "$X":{"gold":">20"},
        "$Y":{"target":"$X"}}},
    "action":{
        "$X":{"target":"$Y"},
        "superfluous":"@remove"}
}


8) Die Aktion kann auch keine Baumvorlage sein, sondern ein Array von Regeln. Jeder von ihnen wird nicht von Grund auf überprüft, sondern mit der anfänglichen Instanziierung, mit der die Aktion aufgerufen wurde. Das heißt, es kann eine ganze Gruppe von Regeln geben, und alle verwenden die X-Variable.



{
    "condition":{
        "player":{
            "$X":{}, "$Y":{"target":"$X"}}},
    "action":[
        {"condition":{}, "action":{}},
        {"condition":{}, "action":{}}]
}


9) Die untergeordnete Regel kann nicht von der Wurzel des Statusbaums aus angewendet werden, sondern von einem Punkt, der während der Anwendung der Aktion erreicht wurde. In diesem Fall verwenden alle Bedingungen und alle Aktionen diesen Punkt als Wurzel. Es sieht aus wie das:



{
    "condition":{
        "player":{
            "$X":{}, "$Y":{"target":"$X"}}},
    "action":{
        "$X":{"@rules":[
            {"condition":{}, "action":{}},
            {"condition":{}, "action":{}}]}
}


10) Die Wiederholung der Regel könnte als ein anderer Knoten angegeben werden, wodurch bei Bedarf eine Rekursion begrenzter Tiefe erreicht wird. In der Praxis war eine solche Entscheidung jedoch in der Regel nicht erforderlich. Es kann auch verwendet werden, um eine Reihe von Regeln nach Bedarf zu wiederholen, indem Sie sie in eine Aktion einfügen:



{
    "condition":{},
    "action":{},
    "repeat":5
}


11) Der Regelbaum konnte aus mehreren JSON-Dateien geladen werden, ihre Baumstruktur wurde einfach übereinander gelegt. Es war praktisch, die Regeln in separate sinnvolle Blöcke zu unterteilen. Wahrscheinlich wäre auch ein Include nützlich, jetzt erinnere ich mich nicht mehr daran, wie es mit uns arrangiert wurde.



12) Protokollierung! Jede Regel könnte einen "@log": true-Knoten haben, was dazu führte, dass diese Regel im Protokoll, das den Lösungsprozess beschreibt, sehr detailliert zu scheißen begann. Welche Konkretisierungen versuchen wir, welche Zweige des Denkens werden unterdrückt und warum. Die Protokollierung war hierarchisch, dh die verschachtelte Regel könnte "@log" sein: false und alles, was darin und darunter geschieht, wird nicht protokolliert. Im Idealfall möchte ich, dass dieser Knoten an einer beliebigen Stelle im Baum der Bedingungen belassen werden kann, um nur zu sehen, was in einer Ebene der Vorlage geschieht, aber ich scheine eine solche Erweiterung nicht abgeschlossen zu haben. Vielleicht verlief das Debuggen ohne es gut, so dass es auf "eines Tages" verschoben wurde.



13) Tippen. Das Spielzeug war so alt, dass einige der heutigen Programmierer nicht einmal geboren wurden. Es wurde in ActionScript2 geschrieben, das über eine dynamische Typisierung und Vererbung durch Prototypen verfügt, die direkt zur Laufzeit verfügbar sind. Von den modernen Sprachen, die gehört werden, funktioniert nur Python auf diese Weise. Es ist jedoch nicht besonders schwierig, sich an diese Idee zu binden. Ich würde dies mit dem Schlüsselsymbol ':' wie folgt tun: "$ X: int", aber es kann schwierig sein, wenn das erste Vorkommen der Variablen keinen der angegebenen Typen hatte. Außerdem kann es zu Verwechslungen mit dem ternären Operator kommen.



Wie sie sagen, war es auf dem Papier glatt, aber für den praktischen Gebrauch waren verschiedene Krücken erforderlich. Hier sind die, an die ich mich erinnere:



14) Ein und derselbe Knoten könnte nicht durch eine, sondern durch mehrere Bedingungen überprüft werden. Eine solche Bedingung überprüfte beispielsweise zuerst, ob mehr als 20 Geld vorhanden waren, und gab dann die Variable an, in der dieser Geldbetrag dargestellt wurde. Das Dienstsymbol '@', wenn es sich nicht am Anfang der Zeile befindet, bedeutete einen erneuten Eintritt in den Knoten, und die weitergehende Wiedereintrittskennung war in keiner Weise nützlich. Vielleicht wurde ein Service-Symbol verwendet und ein anderes, aber meiner Meinung nach hindert Sie nichts daran, dieses zu verwenden:



{
    "player":{
        "$X":{"gold":"<20", "gold@cnt":"$COUNT"}
    }
}


15) Es waren arithmetische Operationen erforderlich, die ohne Verwendung eines Knotens ausgeführt werden konnten. Nach der Tradition des Prologs wurden sie als "_" bezeichnet, und es kann viele davon geben:



{
    "_":"$SUM=$A+$B",
    "_@check":"@SUM <20"
}


16) Da es einen Überprüfungspass im Baum gibt, wurde auch ein Abstieg über das Schlüsselwort "@parent" nach unten vorgenommen. Dies trug natürlich nicht zur Lesbarkeit bei, aber es war unmöglich, darauf zu verzichten. Hier bietet sich natürlich direkt ein Analogon der Pfadfunktion an, das an die angegebene Stelle im Baum umleiten würde, aber ich erinnere mich nicht, ob ich es am Ende geschafft habe, es zu implementieren oder nicht:



{
    "condition":{
        "player":{
            "$X":{}, "$Y":{"target":"$X"}}},
    "action":{
        "$X":{"rules":[
            {
                "condition":{
                    "@parent":{"@parent":{"…":"…"}}
            }
        ]},
    }
}


17) Die Aktion kann jetzt direkt eine Klassenmethode abrufen. Dies ist so ein Kick in den Bauch der Lesbarkeit, und ich würde ein Analogon von #include bevorzugen, aber so wie es ist, können Sie die Wörter aus dem Song nicht wegwerfen. Ich frage mich, ob ich in der Praxis darauf verzichten kann, wenn ich die Bibliothek jetzt in C # wiederbelebe.



18) Die Regel hat jetzt eine zusätzliche Einstellung, um die Aktion nicht für alle gefundenen Konkretionen zu wiederholen, sondern nur für die erste. Ich erinnere mich jetzt nicht, wie es hieß, aber aus irgendeinem Grund war diese Krücke für einige Regeln nützlich.



Nutzungsergebnisse



Sobald die Bibliothek aktiv genutzt wurde, wurden alle KI-Shki schnell darauf übertragen, und dies ermöglichte es, doppelt so intelligente KI zu haben und gleichzeitig dreimal weniger Programmierressourcen aufzuwenden. Es hat sehr geholfen, dass die Zwischendaten der AI-Skala direkt im Baum gespeichert wurden. Insbesondere schrieben die Regeln selbst Informationen über die Karten jeder Farbe, die das Spiel verlassen hatten, direkt im Spielstatusbaum.



Bereits im nächsten Projekt wurden die Spielregeln überprüft und mögliche Bewegungen von jeder Position auf dieselbe Engine verschoben. Und im Allgemeinen wäre dies nicht nur für Rapid Prototyping, sondern auch für Spiele, in denen es einfach viele Regeln gibt, eine sehr nützliche Sache. Am Ende können herunterladbare JSONs mit Logik die Hälfte dessen ersetzen, was Programmierer mit Code tun, und auch an Flexibilität gewinnen.



In Bezug auf die Ausführungsgeschwindigkeit war all dies natürlich dem Durcheinander von ifs deutlich unterlegen, insbesondere bei der Implementierung auf AS2 mit seinen Prototypen und dynamischen Objekten, aber nicht so sehr, dass es nicht in die Produktion eingeführt werden konnte.



Der nächste Schritt bestand darin, die Regelprüfung zu übertragen und die Aktion für die KI auf den Clientcomputer zu bestimmen. Damit sich die Spieler gegenseitig überprüfen. Und ich habe mir sogar einen solchen Algorithmus ausgedacht, um dies zu tun, obwohl uns die Werte der feindlichen Karten nicht bekannt sind, aber das war eine ganz andere Geschichte.



Viele Jahre vergingen, ich wechselte ein Dutzend Mal den Job und jedes Mal, wenn ich meinen Lebenslauf aktualisierte, ging ich zu toox.com und war überrascht, dass mein Job noch in Betrieb war. Ich bin sogar vorbeigekommen, um ein anderes Spiel zu spielen. Und als ich einmal in Belot war, stieß ich versehentlich auf einen Kartensatz mit der maximal möglichen Anzahl von Punkten. Die Wahrscheinlichkeit, einen solchen Satz zu erhalten, beträgt eins zu drei Millionen.



Eines Tages werde ich meinen Willen in einer Handvoll sammeln und ein modernes Remake von Logrus für C # und Unity3d machen, zum Beispiel für den sechseckigen Strategen, von dem ich träume. Aber es wird nicht heute sein, heute werde ich ins Bett gehen. Die Pflicht, Ideen zu verbreiten, die es wert sind, verbreitet zu werden, wurde erfolgreich erfüllt.



Abschließend ein paar Anekdoten



Wir befanden uns im Nowosibirsk Academgorodok. Wir haben ein Büro am Institut gemietet. Und der Kunde ist Franzose, mit den örtlichen Gepflogenheiten völlig unbekannt. Und dann, im dritten oder vierten Monat der gemeinsamen Arbeit, besucht er uns, um sich kennenzulernen. Ich habe am Wochenende im örtlichen Hotel "Zolotaya Dolina" eingecheckt und am Montag, sagt er zum Manager, treffen wir mich um zehn Uhr morgens in einem Taxi, wir gehen mit den Programmierern, um uns kennenzulernen. Und nimm Vovchik und komm um 10 Uhr. Im Allgemeinen fahren sie zum Institut, klopfen an die Tür, und von der anderen Seite kommt die Großmutter des Wachmanns und sieht sie völlig verständnislos hinter der verschlossenen Tür an. Zu einem so frühen Zeitpunkt mieteten keine Wissenschaftler oder Programmierer Büros im Gebäude. Sie weckten sie buchstäblich auf.



Und hier ist ein anderer Fall. Irgendwie ruft unser Sebastian Pereira den Manager an und sagt, dass sie es auf wundersame Weise geschafft haben, in den Fernseher einzudringen, und bald werden wir mit unserer Website im Fernsehen gezeigt. Nach ca. 8 Stunden. Also, was tun Sie dort, damit es zuverlässiger funktioniert ... Um die Uhr am 2. Januar ... Es spielt keine Rolle, zu welcher Zeit ... Und so nimmt Vovchik ein Taxi, beginnt, Programmierer in Schlafsälen und Wohnungen zu sammeln, die völlig verschmutzt sind, und bringt sie ins Büro. An diesem Tag sah ich unseren Systemadministrator zum ersten Mal in meinem Leben. Bis zu diesem Zeitpunkt hat er alles ausschließlich aus der Ferne erledigt. Und so haben wir jeden verdreht, der konnte. Insbesondere habe ich dieses ganze System gebrochen, indem ich ein paar Wenns wieder an seinen Platz gebracht habe, und hier sehen wir uns die Anwesenheitsgrafik an und plötzlich sehen wir, wie es anfängt zu steigen. Irgendwo an der x15-Marke stürzte der Server ab. Aber der Administrator sagte, dass alles in Ordnung ist, fiel sanft,jetzt wird er aufstehen. Der Server stürzte an diesem Tag noch dreimal ab.



All Articles