Turmproblem: Wie gehe ich nach der ersten Lösung weiter vor?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Hallo Zusammen,

ich möchte ein Turmproblem mit einem 8x8 Schachbrett behandeln, wo mir das Programm alle möglichen Lösungen ausgibt, wie 8 Türme so platziert werden können, dass sie sich nicht gegenseitig bedrohen, d.h., dass es in jeder Reihe und Linie jeweils nur einen Turm gibt.

Zuerst einmal mein Grundprogramm:

Code: Alles auswählen

class Schachbrett():

    def __init__(self):
        self._schachbrett = [[0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0],\
                             [0,0,0,0,0,0,0,0]]
        self.maxi_reihe = 8
        self.maxi_linie = 8

    def turm_bedroht(self,reihe,linie):
        spielfeld = self._schachbrett
        if reihe >= 0 and reihe <= 7:
            x = reihe    
        else:
            print("Reihe existiert nicht")
            return None
        if linie >= 0 and linie <= 7:
            y = linie  
        else:
            print("Linie existiert nicht")
            return None
        if spielfeld[x][y] == "t":    
            return True  
        if "t" in spielfeld[x]:
            return True
        if "t" not in spielfeld[x]:
            for zahl in range(0,len(spielfeld)):
                if spielfeld[zahl][y] == "t":
                    return True      
            else:
                return False


    def setze_tuerme(self, anfangsreihe, anfangslinie):
        self._ergebnis = []
        self._x = anfangsreihe
        self._y = anfangslinie
        if self._x <= 7 and self._y <= 7:
            self._schachbrett[self._x][self._y] = "t"
            return s.setze_tuerme(anfangsreihe+1, anfangslinie+1)
        if self._x > 7 and self._y > 7:
            self._x -= 1
            self._y -= 1
            print()
            print("Spielfeld:")
            print()
            for i in self._schachbrett:
                print(i)
            print()
        self._ergebnis.append(self._schachbrett)


    def anzahl_tuerme(self):
        self._zaehler = 0
        for i in self._schachbrett:
            if "t" in i:
                self._zaehler += 1
        self._anzahl =  self._zaehler
        return self._zaehler
        print()


  
    def ergebnis_formatiert(self):
        print("Ergebnis:")
        print()
        for i in self._ergebnis:
            for i in self._schachbrett:
                print(i)


    def turmproblem(self):
        letzer_turm_x = self._x
        letzter_turm_y = self._y
        s.turm_entfernen(self._x,self._y)
        return s.ergebnis_formatiert()


    def turm_entfernen(self, reihe, linie):
        if reihe < self.maxi_reihe and linie < self.maxi_linie:
            self._x = reihe
            self._y = linie
        if self._schachbrett[self._x][self._y] == "t":
            self._schachbrett[self._x][self._y] = 0
            s.feld_formatieren(self._schachbrett)
            print()
            return True
        else:
            return False
            
            
s = Schachbrett()
 
s.setze_tuerme(0,0)
        
 

Ich habe also schon eine Funktion geschrieben, die überprüft, ob ein bestimmtes Feld bedroht ist, oder nicht (turm_bedroht) und eine Funktion anzahl_tuerme, die ich später bei der Rekursion benutzen wollte, damit ich weiß, wann ich eine neue Lösung gefunden habe, nämlich dann, wenn ich 8 Türme ohne Probleme gesetzt habe.

Außerdem habe ich die "setze_tuerme" Funktion, mit der ich quasi meine erste Lösung habe. Ich setze von oben links ([0,0]) bis unten rechts ([7,7]) -also diagonal- die Türme und habe dann meine erste Lösung.

Nun weiß ich jedoch nicht recht, wie ich weiter vorgehen muss, um alle möglichen Lösungen durchzuspielen. Könnte mir jemand eventuell die Vorgehensweise (rekursiv) schildern, ohne den dazugehörigen Quellcode anzugeben? Ich würde es dann gerne selbst in der Funktion "turmproblem" programmieren, weiß jedoch nicht genau wie ich das machen soll.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde da glaube ich anders vorgehen. Mit einer rekursiven Funktion kannst du einfach alle moeglichen Turmplazierungen erzeugen. Das Rezept dazu sieht grob so aus:

- starte mit einer Menge aller Spalten und Zeilen
- iterier ueber die Zeilen und dann Spalten
- die daraus resultierende Position ist die des ersten Turms. Pack die in eine Liste
- ruf die Funktion rekursiv auf, wobei die Menge der Spalten und Zeilen entsprechend der bestehenden Wahl verringert wird.
- gib die aktuelle Position plus die rekursiven Positionen aus.
- Rekursionsabbruch ist eine leere Menge an Spalten/Zeilen-Positionen. Gib eine leere Liste zurueck.

Auf die Art und weise sollten eigentlich immer nur valide Stellungen generiert werden, eine Pruefung ist eigentlich nicht mehr notwendig.
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Hallo,

Vielen Dank erstmal für die Antwort. Leider muss ich das Problem nach dem vorgegeben Schema lösen
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: noch ein paar Anmerkungen zu Deinem Code.
Die Backslashes bei `self._schachbrett` sind überflüssig, da durch die Klammerung schon eindeutig klar ist, dass die Zeilen fortgesetzt werden müssen.
`maxi_reihe` und `maxi_linie` werden nur an einer Stelle benutzt, obwohl an vielen anderen Stellen darauf explizit geprüft wird. Weder das eine noch das andere sind nötig, wenn man die Länge der Listen in `_schachbrett` benutzt.

In `turm_bedroht` würde ich nicht prüfen, ob reihe oder linie innerhalb der Listengrenzen sind, sondern einfach nur den IndexError durchgeben.
Die drei restlichen `if` kann man zu einem if-else reduzieren. for .. in range(len(..)) ist ein Antipattern, das heißt, etwas das unnötig kompliziert ist, weil es eine direkte Lösung gibt, das iterieren über eine Liste. Die Methode reduziert sich also zu:

Code: Alles auswählen

    def turm_bedroht(self, reihe, linie):
        if "t" in self._spielfeld[reihe]:
            return True
        else:
            for zeile in self._spielfeld:
                if zeile[linie] == "t":
                    return True      
            return False
In `setze_tuerme` ist es unsinnig, anfangsreihe und anfangslinie an self._x und self._y zu binden. Das wird gar nicht gebraucht. In `anzahl_tuerme` ist `i` ein schlechter Name für eine Zeile des Schachbretts. Sowohl zaehler als auch anuahl sollten keine Attribute sein. Das `print` wird nie erreicht.

Bei `ergebnis_formatiert` ist die äußere for-Schleife Quatsch, und `i` wieder kein guter Name.
Was soll `turmproblem` machen? Und für was sind `letzer_turm_x` und `letzter_turm_y` da?

Nach welchem Schema sollst Du das Problem lösen? Was sind die genauen Bedingungen?
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Danke ebenfalls für deine Hilfe.

Die Tipps werde ich mir zu Herzen nehmen. DasVerfahren soll so ablaufen:

Zuerst setze ich rekursiv 8 Türme und zwar beginnend oben links und dann diagonal nach rechts unten. Mit letzter_turm_x und letzter_turm_y merke ich mir die Koordinaten des Turmes unten rechts, da ich den als letztes gesetzt habe. Nun soll ich den letzten Turm löschen und den vorletzten eine Zeile weiter unten hinsetzen. Dann kommt der 8. Turm wieder in die Spalte wie vorher, jedoch in die vorletzte Zeile. Das ganze soll ich so lange machen bis die Turmreihe vom Anfang gespiegelt ist, also der erste Turm unten links ist und die Reihe diagonal nach oben rechts verläuft
Antworten