Freigeisterhaus Foren-Übersicht
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   NutzungsbedingungenNutzungsbedingungen   BenutzergruppenBenutzergruppen   LinksLinks   RegistrierenRegistrieren 
 ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Schachprogrammierung
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen   Drucker freundliche Ansicht    Freigeisterhaus Foren-Übersicht -> DAU's Paradise
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1959867) Verfasst am: 24.10.2014, 22:19    Titel: Schachprogrammierung Antworten mit Zitat

Thread eröffnet auf Anregung aus dem Chat.

Ich möchte hier demonstrieren, wie man ein einfaches Schachprogramm in Python schreiben kann. Casual glaubt mir nämlich nicht, dass das gar nicht so kompliziert ist. Das Programm werde ich möglichst leicht verständlich gestalten, auch wenn das zu Lasten der Performance geht.

Im Prinzip müssen wir folgende Teilaufgaben lösen:
1. Brettdarstellung: Wir brauchen eine Datenstruktur für Stellungen und ihre Metainformationen (z.B. wer am Zug ist).
2. Stellungsbewertung: Wir müssen bewerten, wer im Vorteil ist und wie groß dieser Vorteil in Bauerneinheiten ist.
3. Zuggenerierung: Für jede Stellung müssen wir die möglichen Züge auflisten.
4. Suche nach dem besten Zug mit dem Minimax-Algorithmus (evtl. mit Alpha-Beta-Pruning, mal schauen)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Casual3rdparty
dauerhaft gesperrt



Anmeldungsdatum: 21.07.2012
Beiträge: 6255

Beitrag(#1959868) Verfasst am: 24.10.2014, 22:21    Titel: Antworten mit Zitat

mal sehen, ob Bravopunk mitmacht. Sehr glücklich
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
AdvocatusDiaboli
Öffentlicher Mobber



Anmeldungsdatum: 12.08.2003
Beiträge: 26367
Wohnort: München

Beitrag(#1959871) Verfasst am: 24.10.2014, 22:27    Titel: Antworten mit Zitat

Ihr seid zu oft allein im Chat. Das bringt euch auf verrückte Ideen. Als passionierter Schachspieler unterstütze ich euer Projekt natürlich ideell. In den 90ern habe ich mich auch mal damit theoretisch beschäftigt.
_________________
Triggerwarnung: Der toxische Addi hat gepostet. Oh, zu spät, Sie haben das schon gelesen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Casual3rdparty
dauerhaft gesperrt



Anmeldungsdatum: 21.07.2012
Beiträge: 6255

Beitrag(#1959872) Verfasst am: 24.10.2014, 22:33    Titel: Antworten mit Zitat

AdvocatusDiaboli hat folgendes geschrieben:
....90ern habe ich mich auch mal damit theoretisch beschäftigt.

awaaaaaaaa bist du aaaaalt. kannst du noch ohne krückstock gehen?
so, addi ist also Schirmherr.
Sehr glücklich

ich glaube das gehört hier noch rein:
http://xkcd.com/353/

jetzt fehlt mir noch das programm, dass nocq zum download empfohlen hat, im chat.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
AdvocatusDiaboli
Öffentlicher Mobber



Anmeldungsdatum: 12.08.2003
Beiträge: 26367
Wohnort: München

Beitrag(#1959875) Verfasst am: 24.10.2014, 22:39    Titel: Antworten mit Zitat

Casual3rdparty hat folgendes geschrieben:
AdvocatusDiaboli hat folgendes geschrieben:
....90ern habe ich mich auch mal damit theoretisch beschäftigt.

awaaaaaaaa bist du aaaaalt. kannst du noch ohne krückstock gehen?
so, addi ist also Schirmherr.
Sehr glücklich

ich glaube das gehört hier noch rein:
http://xkcd.com/353/

jetzt fehlt mir noch das programm, dass nocq zum download empfohlen hat, im chat.


Ja, ich mach natürlich mit. Sehr glücklich ich hatte damals die dumme Idee, ein Schachprogramm in Basic zu schreiben und ein Buch über Schachprogramme gelesen. Hab das glaub ich nach 1 Tag aufgegeben. Es gab sogar mal ein Schachmagazin über Computerschach. Das habe ich gerne konsumiert.
_________________
Triggerwarnung: Der toxische Addi hat gepostet. Oh, zu spät, Sie haben das schon gelesen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Casual3rdparty
dauerhaft gesperrt



Anmeldungsdatum: 21.07.2012
Beiträge: 6255

Beitrag(#1959879) Verfasst am: 24.10.2014, 22:49    Titel: Antworten mit Zitat

AdvocatusDiaboli hat folgendes geschrieben:
Casual3rdparty hat folgendes geschrieben:
AdvocatusDiaboli hat folgendes geschrieben:
....90ern habe ich mich auch mal damit theoretisch beschäftigt.

awaaaaaaaa bist du aaaaalt. kannst du noch ohne krückstock gehen?
so, addi ist also Schirmherr.
Sehr glücklich

ich glaube das gehört hier noch rein:
http://xkcd.com/353/

jetzt fehlt mir noch das programm, dass nocq zum download empfohlen hat, im chat.


Ja, ich mach natürlich mit. Sehr glücklich ich hatte damals die dumme Idee, ein Schachprogramm in Basic zu schreiben und ein Buch über Schachprogramme gelesen. Hab das glaub ich nach 1 Tag aufgegeben. Es gab sogar mal ein Schachmagazin über Computerschach. Das habe ich gerne konsumiert.


in den neunzehnhundertneunzigern war München das zentrum der schachcomputerentwicklung mit Mephisto:
http://www.schach-computer.info/wiki/index.php/Mephisto
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1959884) Verfasst am: 24.10.2014, 22:57    Titel: Antworten mit Zitat

Brettdarstellung

Eine einfache Brettdarstellung ginge so: Wir schreiben eine Liste mit 64 Zahlen. Negative Zahlen stehen für schwarze Figuren, positive für weiße und 0 für leere Felder. Wir erweitern das aber auf 120 Felder, so dass das echte Schachbrett in der Mitte ist. Die Randfelder sind "Lava", auf die keine Figur ziehen darf. Warum wir das machen, wird später bei der Zuggenerierung klar. SPOILER: Wir schließen damit Züge über den Brettrand aus.

So schaut das im Code aus:

Code:

symbols = {
    6: 'K', 5: 'D', 4: 'L', 3: 'S', 2: 'T', 1: 'B',
    -6: 'k', -5: 'd', -4: 'l', -3: 's', -2: 't', -1: 'b',
    0: '.'
}


long_index = [
    21, 22, 23, 24, 25, 26, 27, 28,
    31, 32, 33, 34, 35, 36, 37, 38,
    41, 42, 43, 44, 45, 46, 47, 48,
    51, 52, 53, 54, 55, 56, 57, 58,
    61, 62, 63, 64, 65, 66, 67, 68,
    71, 72, 73, 74, 75, 76, 77, 78,
    81, 82, 83, 84, 85, 86, 87, 88,
    91, 92, 93, 94, 95, 96, 97, 98,
]


class Position:
    def __init__(self):
        self.board = [
            -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
            -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
            -7, -2, -3, -4, -5, -6, -4, -3, -2, -7,
            -7, -1, -1, -1, -1, -1, -1, -1, -1, -7,
            -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
            -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
            -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
            -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
            -7,  1,  1,  1,  1,  1,  1,  1,  1, -7,
            -7,  2,  3,  4,  5,  6,  4,  3,  2, -7,
            -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
            -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
        ]
        self.player = 1
        self.castling = [True, True, True, True]
        self.en_passant = None
        self.halfmove_clock = 0
   
    def __str__(self):
        s = ''
        for i in range(64):
            if i % 8 == 0:
                s += str(8 - i // 8) + ' '
            s += symbols[self.board[long_index[i]]] + ' '
            if i % 8 == 7:
                s += '\n'
        s += '  a b c d e f g h \n'
        return s


print(Position())


Bitte nicht täuschen lassen: self.board ist eindimensional, auch wenn ich die Liste verdächtig zweidimensional aussehen lasse.
6 = weißer König
5 = weiße Dame
4 = weißer Läufer
3 = weißer Springer
2 = weißer Turm
1 = weißer Bauer
-6 = schwarzer König
-5 = schwarze Dame
-4 = schwarzer Läufer
-3 = schwarzer Springer
-2 = schwarzer Turm
-1 = schwarzer Bauer
0 = leer
-7 = Lava

Diese Liste können wir auf zweierlei Art durchnummerieren: Alle Felder von 0 bis 119 (ich nenne es mal langer Index) oder nur die echten Felder von 0 bis 63 (kurzer index). Manchmal werden wir einen kurzen in einen langen Index umrechnen müssen. Dafür könnten wir eine Funktion schreiben, aber ich habe hier einen kleinen Trick angewendet. Diese Funktion hätte nämlich nur 64 mögliche Inputs und Outputs, also können wir einfach eine Liste mit den 64 Outputs verwenden.

Ich habe der Klasse eine Methode __str__ gegeben, damit wir die Stellung als ASCII-Art ausgeben können. Großbuchstaben stehen für weiße Figuren, Kleinbuchstaben für schwarze. Versucht ruhig mal diesen Code laufen zu lassen, ihr benötigt Python 3.x dazu.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1959887) Verfasst am: 24.10.2014, 23:20    Titel: Antworten mit Zitat

Ach ja: self.player ist natürlich der Spieler am Zug. 1 ist weiß, -1 ist schwarz. Auf die Art können wir den Spieler im Bedarfsfall leicht umschalten:

Code:
self.player = -self.player
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1959919) Verfasst am: 25.10.2014, 09:08    Titel: Antworten mit Zitat

Stellungsbewertung

Wir brauchen eine Funktion, die eine Stellung in Zentibauern bewertet. Positive Zahlen sollen dabei für einen weißen Vorteil stehen, negative für einen schwarzen. Eine einfache Vorgehensweise sind Piece-Square-Tables: Wir geben jeder Figur einen Grundwert und je nachdem auf welchem Feld sie sich befindet einen Bonus oder Abzug. Wir könnten natürlich lang und breit diskutieren, welche Figur wo wieviel Bonus oder Abzug kriegen soll, aber ich übernehme einfach mal die Piece-Square-Tables von Tomasz Michniewski:

https://chessprogramming.wikispaces.com/Simplified+evaluation+function

Code:

white_king_table = (
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -20, -30, -30, -40, -40, -30, -30, -20,
    -10, -20, -20, -20, -20, -20, -20, -10,
     20,  20,   0,   0,   0,   0,  20,  20,
     20,  30,  10,   0,   0,  10,  30,  20,
)


white_king_endgame_table = (
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -20, -30, -30, -40, -40, -30, -30, -20,
    -10, -20, -20, -20, -20, -20, -20, -10,
     20,  20,   0,   0,   0,   0,  20,  20,
     20,  30,  10,   0,   0,  10,  30,  20,
)


white_queen_table = (
    -20, -10, -10,  -5,  -5, -10, -10, -20,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -10,   0,   5,   5,   5,   5,   0, -10,
     -5,   0,   5,   5,   5,   5,   0,  -5,
      0,   0,   5,   5,   5,   5,   0,  -5,
    -10,   5,   5,   5,   5,   5,   0, -10,
    -10,   0,   5,   0,   0,   0,   0, -10,
    -20, -10, -10,  -5,  -5, -10, -10, -20,
)


white_bishop_table = (
    -20, -10, -10, -10, -10, -10, -10, -20,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -10,   0,   5,  10,  10,   5,   0, -10,
    -10,   5,   5,  10,  10,   5,   5, -10,
    -10,   0,  10,  10,  10,  10,   0, -10,
    -10,  10,  10,  10,  10,  10,  10, -10,
    -10,   5,   0,   0,   0,   0,   5, -10,
    -20, -10, -10, -10, -10, -10, -10, -20,
)


white_knight_table = (
    -20, -10, -10, -10, -10, -10, -10, -20,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -10,   0,   5,  10,  10,   5,   0, -10,
    -10,   5,   5,  10,  10,   5,   5, -10,
    -10,   0,  10,  10,  10,  10,   0, -10,
    -10,  10,  10,  10,  10,  10,  10, -10,
    -10,   5,   0,   0,   0,   0,   5, -10,
    -20, -10, -10, -10, -10, -10, -10, -20,
)


white_rook_table = (
      0,   0,   0,   0,   0,   0,   0,   0,
      5,  10,  10,  10,  10,  10,  10,   5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
      0,   0,   0,   5,   5,   0,   0,   0,
)


white_pawn_table = (
      0,   0,   0,   0,   0,   0,   0,   0,
     50,  50,  50,  50,  50,  50,  50,  50,
     10,  10,  20,  30,  30,  20,  10,  10,
      5,   5,  10,  25,  25,  10,   5,   5,
      0,   0,   0,  20,  20,   0,   0,   0,
      5,  -5, -10,   0,   0, -10,  -5,   5,
      5,  10,  10, -20, -20,  10,  10,   5,
      0,   0,   0,   0,   0,   0,   0,   0,
)


black_king_table = (
     20,  30,  10,   0,   0,  10,  30,  20,
     20,  20,   0,   0,   0,   0,  20,  20,
    -10, -20, -20, -20, -20, -20, -20, -10,
    -20, -30, -30, -40, -40, -30, -30, -20,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
)


black_king_endgame_table = (
     20,  30,  10,   0,   0,  10,  30,  20,
     20,  20,   0,   0,   0,   0,  20,  20,
    -10, -20, -20, -20, -20, -20, -20, -10,
    -20, -30, -30, -40, -40, -30, -30, -20,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
    -30, -40, -40, -50, -50, -40, -40, -30,
)


black_queen_table = (
    -20, -10, -10,  -5,  -5, -10, -10, -20,
    -10,   0,   5,   0,   0,   0,   0, -10,
    -10,   5,   5,   5,   5,   5,   0, -10,
      0,   0,   5,   5,   5,   5,   0,  -5,
     -5,   0,   5,   5,   5,   5,   0,  -5,
    -10,   0,   5,   5,   5,   5,   0, -10,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -20, -10, -10,  -5,  -5, -10, -10, -20,
)


black_bishop_table = (
    -20, -10, -10, -10, -10, -10, -10, -20,
    -10,   5,   0,   0,   0,   0,   5, -10,
    -10,  10,  10,  10,  10,  10,  10, -10,
    -10,   0,  10,  10,  10,  10,   0, -10,
    -10,   5,   5,  10,  10,   5,   5, -10,
    -10,   0,   5,  10,  10,   5,   0, -10,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -20, -10, -10, -10, -10, -10, -10, -20,
)


black_knight_table = (
    -20, -10, -10, -10, -10, -10, -10, -20,
    -10,   5,   0,   0,   0,   0,   5, -10,
    -10,  10,  10,  10,  10,  10,  10, -10,
    -10,   0,  10,  10,  10,  10,   0, -10,
    -10,   5,   5,  10,  10,   5,   5, -10,
    -10,   0,   5,  10,  10,   5,   0, -10,
    -10,   0,   0,   0,   0,   0,   0, -10,
    -20, -10, -10, -10, -10, -10, -10, -20,
)


black_rook_table = (
      0,   0,   0,   5,   5,   0,   0,   0,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
     -5,   0,   0,   0,   0,   0,   0,  -5,
      5,  10,  10,  10,  10,  10,  10,   5,
      0,   0,   0,   0,   0,   0,   0,   0,
)


black_pawn_table = (
      0,   0,   0,   0,   0,   0,   0,   0,
      5,  10,  10, -20, -20,  10,  10,   5,
      5,  -5, -10,   0,   0, -10,  -5,   5,
      0,   0,   0,  20,  20,   0,   0,   0,
      5,   5,  10,  25,  25,  10,   5,   5,
     10,  10,  20,  30,  30,  20,  10,  10,
     50,  50,  50,  50,  50,  50,  50,  50,
      0,   0,   0,   0,   0,   0,   0,   0,
)


Die Klasse Position ergänzen wir:

Code:

    def evaluate(self):
        score = 0
        endgame = self.endgame()
        for i in range(64):
            piece = self.board[long_index[i]]
            if piece == 6:
                if endgame:
                    score += white_king_endgame_table[i]
                else:
                    score += white_king_table[i]
            elif piece == 5:
                score += 900 + white_queen_table[i]
            elif piece == 4:
                score += 330 + white_bishop_table[i]
            elif piece == 3:
                score += 320 + white_knight_table[i]
            elif piece == 2:
                score += 500 + white_rook_table[i]
            elif piece == 1:
                score += 100 + white_pawn_table[i]
            elif piece == -6:
                if endgame:
                    score -= black_king_endgame_table[i]
                else:
                    score -= black_king_table[i]
            elif piece == -5:
                score -= 900 + black_queen_table[i]
            elif piece == -4:
                score -= 330 + black_bishop_table[i]
            elif piece == -3:
                score -= 320 + black_knight_table[i]
            elif piece == -2:
                score -= 500 + black_rook_table[i]
            elif piece == -1:
                score -= 100 + black_pawn_table[i]
        return score
   
    def endgame(self):
        white_queens = 0
        white_rooks = 0
        white_minor_pieces = 0
        black_queens = 0
        black_rooks = 0
        black_minor_pieces = 0
        for i in range(64):
            piece = self.board[long_index[i]]
            if piece == 5:
                white_queens += 1
            elif piece == 2:
                white_rooks += 1
            elif piece in (3, 4):
                white_minor_pieces += 1
            elif piece == -5:
                black_queens += 1
            elif piece == -2:
                black_rooks += 1
            elif piece in (-3, -4):
                black_minor_pieces += 1
        white_endgame = white_queens == 0 or white_queens == 1 and white_rooks == 0 and white_minor_pieces <= 1
        black_endgame = black_queens == 0 or black_queens == 1 and black_rooks == 0 and black_minor_pieces <= 1
        return white_endgame and black_endgame
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960094) Verfasst am: 26.10.2014, 07:26    Titel: Antworten mit Zitat

Ein paar Hilfsmethoden für die Klasse Position, die uns gleich bei der Zuggenerierung helfen werden:

Code:

    def capturable(self, square):
        i = self.player * self.board[square]
        return i <= -1 and i >= -6
   
    def capturable_or_empty(self, square):
        i = self.player * self.board[square]
        return i <= 0 and i >= -6
   
    def empty(self, square):
        return self.board[square] == 0
   
    def movable(self, square):
        i = self.player * self.board[square]
        return i >= 1 and i <= 6


Diese Methoden verraten uns, ob sich auf einem Feld eine schlagbare oder ziehbare Figur befindet oder ob es leer ist. Der Parameter square ist ein langer Index.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960095) Verfasst am: 26.10.2014, 07:31    Titel: Antworten mit Zitat

Wir erweitern den Konstruktor, so dass er Kopien von Stellungen machen kann, bei denen aber der andere Spieler am Zug ist:

Code:

    def __init__(self, position=None):
        if position is not None:
            self.board = list(position.board)
            self.player = -position.player
            self.castling = list(position.castling)
            self.en_passant = None
        else:
            self.board = [
                -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
                -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
                -7, -2, -3, -4, -5, -6, -4, -3, -2, -7,
                -7, -1, -1, -1, -1, -1, -1, -1, -1, -7,
                -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
                -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
                -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
                -7,  0,  0,  0,  0,  0,  0,  0,  0, -7,
                -7,  1,  1,  1,  1,  1,  1,  1,  1, -7,
                -7,  2,  3,  4,  5,  6,  4,  3,  2, -7,
                -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
                -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
            ]
            self.player = 1
            self.castling = [True, True, True, True]
            self.en_passant = None


Außerdem eine Methode, die die Stellung kopiert und auf der Kopie einen Zug ausführt:

Code:

    def make_move(self, origin, target):
        move = Position(self)
        move.board[target] = move.board[origin]
        move.board[origin] = 0
        return move


origin und target sind lange Indizes.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960096) Verfasst am: 26.10.2014, 08:16    Titel: Antworten mit Zitat

Wenn der König zieht, dann verändert sich sein langer Index um -11, -10, -9, -1, 1, 9, 10 oder 11. Diese Zahlen nenne ich mal die Offsets des Königs. Für den Springer können wir auch solche Zahlen angeben.

Bei Dame, Läufer und Turm reichen uns die Offsets für ein Feld weite Züge, d.h. diese Offsets deuten nur die möglichen Zugrichtungen an, aber nicht alle möglichen Zielfelder.

Beim Bauern reichen die Offsets für die Schlagzüge, Nichtschlagzüge behandeln wir extra.

Also haben wir jetzt folgende Offsets:

Code:

king_offsets = (-11, -10, -9, -1, 1, 9, 10, 11)
queen_offsets = (-11, -10, -9, -1, 1, 9, 10, 11)
bishop_offsets = (-11, -9, 9, 11)
knight_offsets = (-21, -19, -12, -8, 8, 12, 19, 21)
rook_offsets = (-10, -1, 1, 10)
white_pawn_offsets = (-11, -9)
black_pawn_offsets = (9, 11)


Und damit können wir bei der Zuggenerierung Zielfelder ausrechnen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960097) Verfasst am: 26.10.2014, 08:23    Titel: Antworten mit Zitat

Und jetzt können wir schon eine Methode für die Zuggenerierung schreiben. Wir gehen ganz einfach alle Felder durch und immer wenn wir eine ziehbare Figur finden, gehen wir alle Zielfelder durch und fügen den Zug zur Liste hinzu.

Code:

    def generate_moves(self):
        moves = []
        for i in range(64):
            origin = long_index[i]
            if self.movable(origin):
                # König
                if abs(self.board[origin]) == 6:
                    for offset in king_offsets:
                        target = origin + offset
                        if self.capturable_or_empty(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                # Dame
                elif abs(self.board[origin]) == 5:
                    for offset in queen_offsets:
                        target = origin + offset
                        while self.capturable_or_empty(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if self.capturable(target):
                                break
                            target += offset
                # Läufer
                elif abs(self.board[origin]) == 4:
                    for offset in bishop_offsets:
                        target = origin + offset
                        while self.capturable_or_empty(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if self.capturable(target):
                                break
                            target += offset
                # Springer
                elif abs(self.board[origin]) == 3:
                    for offset in knight_offsets:
                        target = origin + offset
                        if self.capturable_or_empty(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                # Turm
                elif abs(self.board[origin]) == 2:
                    for offset in rook_offsets:
                        target = origin + offset
                        while self.capturable_or_empty(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if self.capturable(target):
                                break
                            target += offset
                # weißer Bauer
                elif self.board[origin] == 1:
                    target = origin - 10
                    if self.empty(target):
                        move = self.make_move(origin, target)
                        moves.append(move)
                        if origin // 10 == 8:
                            target -= 10
                            if self.empty(target):
                                move = self.make_move(origin, target)
                                moves.append(move)
                    for offset in white_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
                # schwarzer Bauer
                elif self.board[origin] == -1:
                    target = origin + 10
                    if self.empty(target):
                        move = self.make_move(origin, target)
                        moves.append(move)
                        if origin // 10 == 3:
                            target += 10
                            if self.empty(target):
                                move = self.make_move(origin, target)
                                moves.append(move)
                    for offset in white_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            move = self.make_move(origin, target)
                            moves.append(move)
        return moves


Wir berücksichtigen jetzt noch nicht alle Zugregeln, aber das kommt auch noch.

Testen wir erst einmal den Zuggenerator:

Code:

root = Position()
children = root.generate_moves()
for child in children:
    print(child.evaluate())
    print(child)


Ausgabe:

Code:

0
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 B . . . . . . .
2 . B B B B B B B
1 T S L D K L S T
  a b c d e f g h

-5
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 B . . . . . . .
3 . . . . . . . .
2 . B B B B B B B
1 T S L D K L S T
  a b c d e f g h

-15
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . B . . . . . .
2 B . B B B B B B
1 T S L D K L S T
  a b c d e f g h

-10
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . B . . . . . .
3 . . . . . . . .
2 B . B B B B B B
1 T S L D K L S T
  a b c d e f g h

-20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . B . . . . .
2 B B . B B B B B
1 T S L D K L S T
  a b c d e f g h

-10
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . B . . . . .
3 . . . . . . . .
2 B B . B B B B B
1 T S L D K L S T
  a b c d e f g h

20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . B . . . .
2 B B B . B B B B
1 T S L D K L S T
  a b c d e f g h

40
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . B . . . .
3 . . . . . . . .
2 B B B . B B B B
1 T S L D K L S T
  a b c d e f g h

20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . B . . .
2 B B B B . B B B
1 T S L D K L S T
  a b c d e f g h

40
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . B . . .
3 . . . . . . . .
2 B B B B . B B B
1 T S L D K L S T
  a b c d e f g h

-20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . B . .
2 B B B B B . B B
1 T S L D K L S T
  a b c d e f g h

-10
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . B . .
3 . . . . . . . .
2 B B B B B . B B
1 T S L D K L S T
  a b c d e f g h

-15
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . . B .
2 B B B B B B . B
1 T S L D K L S T
  a b c d e f g h

-10
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . B .
3 . . . . . . . .
2 B B B B B B . B
1 T S L D K L S T
  a b c d e f g h

0
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . . . B
2 B B B B B B B .
1 T S L D K L S T
  a b c d e f g h

-5
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . B
3 . . . . . . . .
2 B B B B B B B .
1 T S L D K L S T
  a b c d e f g h

0
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 S . . . . . . .
2 B B B B B B B B
1 T . L D K L S T
  a b c d e f g h

20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . S . . . . .
2 B B B B B B B B
1 T . L D K L S T
  a b c d e f g h

20
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . S . .
2 B B B B B B B B
1 T S L D K L . T
  a b c d e f g h

0
8 t s l d k l s t
7 b b b b b b b b
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . . . S
2 B B B B B B B B
1 T S L D K L . T
  a b c d e f g h

Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
NoReply
registrierter User



Anmeldungsdatum: 20.09.2013
Beiträge: 683

Beitrag(#1960172) Verfasst am: 26.10.2014, 15:14    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
Ein paar Hilfsmethoden für die Klasse Position, die uns gleich bei der Zuggenerierung helfen werden:

Code:

    def capturable(self, square):
        i = self.player * self.board[square]
        return i <= -1 and i >= -6
   
    def capturable_or_empty(self, square):
        i = self.player * self.board[square]
        return i <= 0 and i >= -6
   
    def empty(self, square):
        return self.board[square] == 0
   
    def movable(self, square):
        i = self.player * self.board[square]
        return i >= 1 and i <= 6


Diese Methoden verraten uns, ob sich auf einem Feld eine schlagbare oder ziehbare Figur befindet oder ob es leer ist. Der Parameter square ist ein langer Index.


Warum testest du auf i>=-6 bzw. i<=6, wenn du doch ohnehin nur lange Indices zulässt? Defensive Programmierung?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960177) Verfasst am: 26.10.2014, 15:32    Titel: Antworten mit Zitat

NoReply hat folgendes geschrieben:
Warum testest du auf i>=-6 bzw. i<=6, wenn du doch ohnehin nur lange Indices zulässt? Defensive Programmierung?

Das Feld könnte auch Lava sein. Langer Index heißt ja, dass auch die Extrafelder in Frage kommen.

Sonst müsste ich nur schauen, ob's positiv oder negativ ist, ja.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
NoReply
registrierter User



Anmeldungsdatum: 20.09.2013
Beiträge: 683

Beitrag(#1960179) Verfasst am: 26.10.2014, 15:37    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
NoReply hat folgendes geschrieben:
Warum testest du auf i>=-6 bzw. i<=6, wenn du doch ohnehin nur lange Indices zulässt? Defensive Programmierung?

Das Feld könnte auch Lava sein. Langer Index heißt ja, dass auch die Extrafelder in Frage kommen.

Sonst müsste ich nur schauen, ob's positiv oder negativ ist, ja.


Ah ok, dachte langer Index bedeutet, dass du nur Werte aus diesem Array zulässt:

Code:
long_index = [
    21, 22, 23, 24, 25, 26, 27, 28,
    31, 32, 33, 34, 35, 36, 37, 38,
    41, 42, 43, 44, 45, 46, 47, 48,
    51, 52, 53, 54, 55, 56, 57, 58,
    61, 62, 63, 64, 65, 66, 67, 68,
    71, 72, 73, 74, 75, 76, 77, 78,
    81, 82, 83, 84, 85, 86, 87, 88,
    91, 92, 93, 94, 95, 96, 97, 98,
]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960183) Verfasst am: 26.10.2014, 15:50    Titel: Antworten mit Zitat

Das brauche ich nur um gelegentlich einen kurzen Index in einen langen umzurechnen.

Code:
long_index[irgendein_kurzer_Index]


ergibt den zugehörigen langen Index.

Ich hätte vielleicht noch etwas ausführlicher sagen sollen, wozu die Lava-Felder gut sind. Wenn ein Zielfeld Lava ist, dann ergibt capturable_or_empty False und generate_moves ignoriert den Zug dann einfach. Ansonsten müssten wir noch Extra-Code schreiben um Züge über den Brettrand auszuschließen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
NoReply
registrierter User



Anmeldungsdatum: 20.09.2013
Beiträge: 683

Beitrag(#1960186) Verfasst am: 26.10.2014, 16:01    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
Das brauche ich nur um gelegentlich einen kurzen Index in einen langen umzurechnen.

Code:
long_index[irgendein_kurzer_Index]


ergibt den zugehörigen langen Index.

Ich hätte vielleicht noch etwas ausführlicher sagen sollen, wozu die Lava-Felder gut sind. Wenn ein Zielfeld Lava ist, dann ergibt capturable_or_empty False und generate_moves ignoriert den Zug dann einfach. Ansonsten müssten wir noch Extra-Code schreiben um Züge über den Brettrand auszuschließen.


Ok, elegant.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960193) Verfasst am: 26.10.2014, 16:22    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:

Code:

                # schwarzer Bauer
                elif self.board[origin] == -1:
                    target = origin + 10
                    if self.empty(target):
                        move = self.make_move(origin, target)
                        moves.append(move)
                        if origin // 10 == 3:
                            target += 10
                            if self.empty(target):
                                move = self.make_move(origin, target)
                                moves.append(move)
                    for offset in white_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            move = self.make_move(origin, target)
                            moves.append(move)


Wer sieht den Bug?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
NoReply
registrierter User



Anmeldungsdatum: 20.09.2013
Beiträge: 683

Beitrag(#1960205) Verfasst am: 26.10.2014, 17:05    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
alae hat folgendes geschrieben:

Code:

                # schwarzer Bauer
                elif self.board[origin] == -1:
                    target = origin + 10
                    if self.empty(target):
                        move = self.make_move(origin, target)
                        moves.append(move)
                        if origin // 10 == 3:
                            target += 10
                            if self.empty(target):
                                move = self.make_move(origin, target)
                                moves.append(move)
                    for offset in white_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            move = self.make_move(origin, target)
                            moves.append(move)


Wer sieht den Bug?

Spoiler: Markieren: Muss black_pawn_offsets statt white heißen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1960238) Verfasst am: 26.10.2014, 19:19    Titel: Antworten mit Zitat

Erweitern wir make_move so, dass man optional eine Figur angeben kann, in die sich die gezogene Figur verwandeln soll.

Code:

    def make_move(self, origin, target, promotion=None):
        move = Position(self)
        if promotion is not None:
            move.board[target] = promotion
        else:
            move.board[target] = move.board[origin]
        move.board[origin] = 0
        return move


Dann sind jetzt auch Bauernumwandlungen möglich:

Code:

                # weißer Bauer
                elif self.board[origin] == 1:
                    target = origin - 10
                    if self.empty(target):
                        if target // 10 == 2:
                            for promotion in (5, 4, 3, 2):
                                move = self.make_move(origin, target, promotion)
                                moves.append(move)
                        else:
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if origin // 10 == 8:
                                target -= 10
                                if self.empty(target):
                                    move = self.make_move(origin, target)
                                    moves.append(move)
                    for offset in white_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            if target // 10 == 2:
                                for promotion in (5, 4, 3, 2):
                                    move = self.make_move(origin, target, promotion)
                                    moves.append(move)
                            else:
                                move = self.make_move(origin, target)
                                moves.append(move)
                # schwarzer Bauer
                elif self.board[origin] == -1:
                    target = origin + 10
                    if self.empty(target):
                        if target // 10 == 9:
                            for promotion in (-5, -4, -3, -2):
                                move = self.make_move(origin, target, promotion)
                                moves.append(move)
                        else:
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if origin // 10 == 3:
                                target += 10
                                if self.empty(target):
                                    move = self.make_move(origin, target)
                                    moves.append(move)
                    for offset in black_pawn_offsets:
                        target = origin + offset
                        if self.capturable(target):
                            if target // 10 == 9:
                                for promotion in (-5, -4, -3, -2):
                                    move = self.make_move(origin, target, promotion)
                                    moves.append(move)
                            else:
                                move = self.make_move(origin, target)
                                moves.append(move)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961486) Verfasst am: 31.10.2014, 17:18    Titel: Antworten mit Zitat

Ich ändere jetzt generate_moves so, dass en_passant bei einem Doppelschritt des Bauern gesetzt wird.

Code:

                # weißer Bauer
                elif self.board[origin] == 1:
                    target = origin - 10
                    if self.empty(target):
                        if target // 10 == 2:
                            for promotion in (5, 4, 3, 2):
                                move = self.make_move(origin, target, promotion)
                                moves.append(move)
                        else:
                            move = self.make_move(origin, target)
                            moves.append(move)
                            if origin // 10 == 8:
                                target -= 10
                                if self.empty(target):
                                    move = self.make_move(origin, target)
                                    move.en_passant = target
                                    moves.append(move)

(analog natürlich für den schwarzen Bauern)

en_passant ist der lange Index des Bauern, der den Doppelschritt gemacht hat oder None, wenn der letzte Zug kein Doppelschritt war. Jetzt kann ich den Code für En-Passant-Züge schreiben:

Code:

        # en passant
        if self.en_passant is not None:
            if self.player == 1:
                target = self.en_passant - 10
                origin = self.en_passant - 1
                if self.board[origin] == 1:
                    move = self.make_move(origin, target)
                    move.board[self.en_passant] = 0
                    moves.append(move)
                origin = self.en_passant + 1
                if self.board[origin] == 1:
                    move = self.make_move(origin, target)
                    move.board[self.en_passant] = 0
                    moves.append(move)
            else:
                target = self.en_passant + 10
                origin = self.en_passant - 1
                if self.board[origin] == -1:
                    move = self.make_move(origin, target)
                    move.board[self.en_passant] = 0
                    moves.append(move)
                origin = self.en_passant + 1
                if self.board[origin] == -1:
                    move = self.make_move(origin, target)
                    move.board[self.en_passant] = 0
                    moves.append(move)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961499) Verfasst am: 31.10.2014, 17:59    Titel: Antworten mit Zitat

Für die Rochade brauchen wir eine Methode, die uns sagt, ob ein bestimmtes Feld von einem bestimmten Spieler angegriffen wird. Funktioniert im Prinzip ähnlich wie generate_moves nur gewissermaßen umgekehrt. Wir haben ein gegebenes Zielfeld und schauen ob es eine passende Figur auf einem passenden Startfeld gibt.

Code:

    def attacked(self, target, attacker):
        # Königsangriffe
        for offset in king_offsets:
            origin = target - offset
            if attacker * self.board[origin] == 6:
                return True
        # Damenangriffe
        for offset in queen_offsets:
            origin = target - offset
            while True:
                if attacker * self.board[origin] == 5:
                    return True
                elif self.board[origin] != 0:
                    break
                else:
                    origin -= offset
        # Läuferangriffe
        for offset in bishop_offsets:
            origin = target - offset
            while True:
                if attacker * self.board[origin] == 4:
                    return True
                elif self.board[origin] != 0:
                    break
                else:
                    origin -= offset
        # Springerangriffe
        for offset in knight_offsets:
            origin = target - offset
            if attacker * self.board[origin] == 3:
                return True
        # Turmangriffe
        for offset in rook_offsets:
            origin = target - offset
            while True:
                if attacker * self.board[origin] == 2:
                    return True
                elif self.board[origin] != 0:
                    break
                else:
                    origin -= offset
        # weiße Bauernangriffe
        if attacker == 1:
            for offset in white_pawn_offsets:
                origin = target - offset
                if self.board[origin] == 1:
                    return True
        # schwarze Bauernangriffe
        else:
            for offset in black_pawn_offsets:
                origin = target - offset
                if self.board[origin] == -1:
                    return True
        return False
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961502) Verfasst am: 31.10.2014, 18:04    Titel: Antworten mit Zitat

self.castling ist eine Liste mit Rochaderechten, der Reihe nach weiße kurze Rochade, weiße lange Rochade, schwarze kurze Rochade und schwarze lange Rochade. Die Rochaderechte werden nur auf False gesetzt, wenn sie dauerhaft verloren gehen, sie bleiben True, wenn die Rochade nur vorrübergehend nicht möglich ist.

Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
step
registriert



Anmeldungsdatum: 17.07.2003
Beiträge: 22767
Wohnort: Germering

Beitrag(#1961534) Verfasst am: 31.10.2014, 19:56    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?

Nur genau bei den genannten Bedingungen.
_________________
Was ist der Sinn des Lebens? - Keiner, aber Leere ist Fülle für den, der sie sieht.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961537) Verfasst am: 31.10.2014, 20:04    Titel: Antworten mit Zitat

step hat folgendes geschrieben:
alae hat folgendes geschrieben:
Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?

Nur genau bei den genannten Bedingungen.

Ich glaube, ich verstehe deine Antwort nicht. Am Kopf kratzen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
step
registriert



Anmeldungsdatum: 17.07.2003
Beiträge: 22767
Wohnort: Germering

Beitrag(#1961540) Verfasst am: 31.10.2014, 20:23    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
step hat folgendes geschrieben:
alae hat folgendes geschrieben:
Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?
Nur genau bei den genannten Bedingungen.
Ich glaube, ich verstehe deine Antwort nicht. Am Kopf kratzen

OK, noch ein Versuch: Ja, genau dann wenn mindestens eine der von Dir genannten Bedingungen eintritt.

Ich lese übrigens mit, hab sowas früher auch mal zum Üben gemacht, allerdings in C. Hat zwar funktioniert, war aber locker einen Faktor 1000 langsamer als die käuflichen Programme auf derselben HW.
_________________
Was ist der Sinn des Lebens? - Keiner, aber Leere ist Fülle für den, der sie sieht.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961541) Verfasst am: 31.10.2014, 20:25    Titel: Antworten mit Zitat

step hat folgendes geschrieben:
alae hat folgendes geschrieben:
step hat folgendes geschrieben:
alae hat folgendes geschrieben:
Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?
Nur genau bei den genannten Bedingungen.
Ich glaube, ich verstehe deine Antwort nicht. Am Kopf kratzen

OK, noch ein Versuch: Ja, genau dann wenn mindestens eine der von Dir genannten Bedingungen eintritt.

Gesucht ist noch eine dritte Bedingung.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
NoReply
registrierter User



Anmeldungsdatum: 20.09.2013
Beiträge: 683

Beitrag(#1961544) Verfasst am: 31.10.2014, 20:35    Titel: Antworten mit Zitat

alae hat folgendes geschrieben:
step hat folgendes geschrieben:
alae hat folgendes geschrieben:
step hat folgendes geschrieben:
alae hat folgendes geschrieben:
Frage in die Runde: Ein Rochaderecht geht dauerhaft verloren, wenn der zugehörige König gezogen wird oder der zugehörige Turm gezogen wird oder ...?
Nur genau bei den genannten Bedingungen.
Ich glaube, ich verstehe deine Antwort nicht. Am Kopf kratzen

OK, noch ein Versuch: Ja, genau dann wenn mindestens eine der von Dir genannten Bedingungen eintritt.

Gesucht ist noch eine dritte Bedingung.


Für den dauerhaften Verlust gibt es keine dritte Bedinung.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
alae
auf eigenen Wunsch deaktiviert



Anmeldungsdatum: 23.03.2006
Beiträge: 7039

Beitrag(#1961545) Verfasst am: 31.10.2014, 20:37    Titel: Antworten mit Zitat

Doch.

Und wenn ich es verrate, heißt es bestimmt: "Warum bin ich da nicht drauf gekommen?"
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen   Drucker freundliche Ansicht    Freigeisterhaus Foren-Übersicht -> DAU's Paradise Alle Zeiten sind GMT + 1 Stunde
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.



Impressum & Datenschutz


Powered by phpBB © 2001, 2005 phpBB Group