Strona główna Polish Python Coders Group
   Strona główna   Pomoc Zaloguj się Rejestracja  
Witamy, Gość. Zaloguj się lub zarejestruj.
Czy dotarł do Ciebie email aktywacyjny?

Zaloguj się podając nazwę użytkownika, hasło i długość sesji

Aktualności: PyStok #32 - 20 czerwiec 2018, 18:00, Białystok
Szukaj Szukaj
Strony: [1]   Do dołu
Drukuj
Wątek: kółko i krzyżyk - błąd przy cofaniu ruchu  (Przeczytany 154 razy)
« : 09:03 13/06/18 »
marmar Offline
Hello World!

Zobacz profil
*

Reputacja: -1
Wiadomości: 40


Witam
Stworzyłam grę "Kółko i Krzyżyk", wszystko działa poprawnie do momentu gdy cofnę wszystkie ruchy i ponownie postawie gdzieś kółko lub krzyzyk - wtedy moja początkowa plansza zmienia się na plansze z postawionym ruchem i mimo kolejnych cofnięć pozostaje ona ze znakami "o" lub "x".
Przedstawiam swój kod:

#plik main.py
Kod
from game import *
from mementos import *
 
def main():
   g = KolkoKrzyzyk()
   g.printBoard()
   m = Mementos(g.board)
   while g.sign < 10:  
       if g.sign % 2 != 0: #sprawdzenie parzystosci znaku, jesli nie to stawiany jest "x", jesli tak - "o"
           if g.sign >1: #sprawdzenie znaku, jesli > 1, uwzgledniam mozliwosc cofniecia ruchu
               if g.movexAndUndo() == False: # wykonuje cofniecie ruchu
                   m.undo(g.sign -1)
                   g.board = m.getMementos(g.sign -2)
                   g.printBoard()
                   g.decrementSign()
                   print("usowam o z 3")
                   print(g.board)
                   print(m.mementos)
               else:
                   m.addState(g.sign, g.board)
                   (g.win())
                   g.printBoard()
                   g.incrementSign()
                   print(g.board)
                   print(m.mementos)
 
           else:
               g.movex()
               m.addState(g.sign, g.board)
               (g.win())
               g.printBoard()
               print("Dodaje x dwojke")
               g.incrementSign()
               print(g.board)
               print(m.mementos)
       else: #stawiajac "o" g.sign zawsze bedzie >1 wiec nie sprawdzam tego warunku
           if g.moveyAndUndo() == False: #wykonuje cofniecie ruchu
               m.undo(g.sign -1)
               g.board = m.getMementos(g.sign -2)
               g.printBoard()
               print("usuwam x z 2")
               print(g.board)
               print(m.mementos)
               g.decrementSign()
           else:
               m.addState(g.sign, g.board)
               (g.win())
               g.printBoard()
               print("dodaje o na 3")
               g.incrementSign()
               print(g.board)
               print(m.mementos)
 
 
       print("---------------------------------------")
   print("Remis !")
main()


#plik game.py
Kod
import numpy
 
class KolkoKrzyzyk: #tworzy plansze gry bedaca tablica/macierza 3x3 z elementami 1-9
 
   def __init__(self):
       self.board = numpy.array([(1,2,3),(4,5,6),(7,8,9)], dtype = object) #dtype = object pozwala wprowadzic do tablicy element typu str
       self.sign = 1 #znak ustala jaki ruch jest wykonywany, gdy jest parzysty dodawane jest "o", w przeciwnym wypadku "x"
 
   def printBoard(self):
       for item in self.board:
           print(" ".join(map(str,item)))
 
   def movex(self): #zamiana wybranego elementu tabeli na "x"
       self.step = input("Wykonaj ruch podajac numer:")
       self.board[(numpy.where(self.board == self.step))] = "x"
 
   def movey(self): #zamiana wybranego elementu tabeli na "o"
       self.step = input("Wykonaj ruch podajac numer: ")
       self.board[(numpy.where(self.board == self.step))] = "o"
 
   def movexAndUndo(self): #zamiana wybranego elementu tabeli na "x" w sytuacji gdy mozliwe jest cofniecie ruchu czyli gdy znak self.sign > 1
       self.step = raw_input("Wykonaj ruch podajac numer lub wcisnij 'c' aby cofnac ruch ")
 
       if self.step != "c":
           self.step = int(self.step)
           self.board[(numpy.where(self.board == self.step))] = "x"
           return True
       return False
 
   def moveyAndUndo(self): #zamiana wybranego elementu tabeli na "o", w sytuacji gdy mozliwe jest cofniecie ruchu, czyli gdy znak self.sign > 1
       self.step = raw_input("Wykonaj ruch podajac numer lub wcisnij 'c' aby cofnac ruch ")
       if self.step != "c":
           self.step = int(self.step)
           self.board[(numpy.where(self.board == self.step))] = "o"
           return True
       return False
 
   def incrementSign(self): #inkrementacja znaku self.sign
       self.sign += 1
 
   def decrementSign(self): #dekrementacja znaku self.sign
       self.sign -= 1
 
   def win(self): #sprawdzenie czy ktorys gracz zwyciezyl
       if (self.board[0][0]=="x" and self.board[0][1]=="x" and self.board[0][2] == "x") or (self.board[1][0]=="x" and self.board[1][1]=="x" and self.board[1][2] == "x" ) or (self.board[2][0]=="x" and self.board[2][1]=="x" and self.board[2][2]== "x") or (self.board[0][0]=="x" and self.board[1][0] =="x" and self.board[2][0]== "x") or (self.board[0][1]=="x" and self.board[1][1]=="x" and self.board[2][1]=="x") or (self.board[0][2]=="x" and self.board[1][2]=="x" and self.board[2][2]=="x") or (self.board[0][0]=="x" and self.board[1][1]=="x" and self.board[2][2]=="x") or (self.board[0][2]=="x" and self.board[1][1]=="x" and self.board[2][0]=="x"):
           print(self.board)
           print("Zwycieza x")
           exit()
 
 
 
       if (self.board[0][0]=="y" and self.board[0][1]=="y" and self.board[0][2] == "y") or (self.board[1][0]=="y" and self.board[1][1]=="y" and self.board[1][2] == "y" ) or (self.board[2][0]=="y" and self.board[2][1]=="y" and self.board[2][2]== "y") or (self.board[0][0]=="y" and self.board[1][0] =="y" and self.board[2][0]== "y") or (self.board[0][1]=="y" and self.board[1][1]=="y" and self.board[2][1]=="y") or (self.board[0][2]=="y" and self.board[1][2]=="y" and self.board[2][2]=="y") or (self.board[0][0]=="y" and self.board[1][1]=="y" and self.board[2][2]=="y") or (self.board[0][2]=="y" and self.board[1][1]=="y" and self.board[2][0]=="y"):
           print(self.board)
           print("Zwycieza y")
           exit()
 


#plik mementos.py
Kod
import numpy
class Mementos: #tworzenie slownika gdzie klucze to numery ruchow a wartosci to stany planszy gry po kazdym wykonanym ruchy
 
   def __init__(self, mainboard):
       self.mementos = dict()
       self.mementos[0] = numpy.copy(mainboard) #dodanie poczatkowego stanu gry, jako ruch zerowy
 
   '''def printMemento(self, r): #wypisanie planszy gry
       for item in self.mementos[r]:
           print(" ".join(map(str, item)))'
''
 
   def addState(self, r, state ): #dodanie do slownika kopi stanu gry
       self.mementos[r] = numpy.copy(state)
 
   def undo(self, r): #usuniecie elementu slownika (pary klucz:wartosc)
       del self.mementos[r]
 
   def getMementos(self, r): #wydobycie ze slownika wartosc(stan gry) danego klucza r(numer ruchu)
       return(self.mementos[r])
 
 

Bardzo mi zależy na dokończeniu gry, lecz zupełnie nie wiem gdzie leży błąd.
Proszę o pomoc.
Zapisane
« Odpowiedz #1 : 16:02 14/06/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 245


Nie wiem czy dobrze cię zrozumiałem.

W pewnym momencie gry, cofasz wszystkie ruchy.
Następnie wprowadzasz kilka ruchów.
I w tym momencie już nie działa cofanie.
Tak?

A co w przypadku gdy nie cofasz wszystkich?
Bo jeśli nie będzie się wykrzaczać, to musisz z jakiegoś powodu wychodzić z warunku ;p.
Kod
if g.sign >1: #sprawdzenie znaku, jesli > 1, uwzgledniam mozliwosc cofniecia ruchu
 
Prawdopodobnie dopuszczasz cofnięcie poniżej jeden np. na zero - postawisz 'x' które zinkrementuje wartość sign na 1.
Kod
        else: #stawiajac "o" g.sign zawsze bedzie >1 wiec nie sprawdzam tego warunku
 
Za dużo do przeglądania błędu konstrukcyjnego, zwłaszcza że dużo można uprościć ;P. Jeśli gdzieś to o czym napisałem regulujesz w pozostałych plikach, to wybacz, spróbuję wtedy je przejrzeć.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #2 : 19:11 16/06/18 »
marmar Offline
Hello World!

Zobacz profil
*

Reputacja: -1
Wiadomości: 40


Znak zawsze jest większy od 0 więc nie wychodzę z warunku.
Wszystkie plansze przechowuje w słowniku, na samym początku klucz to 0 a wartość to plansza z cyframi od 1 do 9. Przy każdym wykonanym ruchu do słownika dodaję plansze z tym ruchem, gdzie kluczem jest znak (g.sign), a przy każdym cofnięciu usuwam ostatnią plansze.
Problem polega na tym ze gdy cofnę wszystkie ruchy i dojdę defakto do początku gry, a następnie ponownie dodaje ruch to pierwszym elementem słownika staje się klucz  0 i wartość która jest planszą gry z dodanym ruchem (zamiast planszy z samymi cyframi), dodaje kolejny ruch - wartość pierwszego elementu zmienia się na plansze z dwoma ruchami.

Zapisane
« Odpowiedz #3 : Wczoraj o 14:54 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 245


Ok, tak więc napiszę kod (będzie dla mnie szybciej napisać poprawnie niż to poprawiać) na dniach i dam ci do przeanalizowania Uśmiech.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #4 : Wczoraj o 22:41 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 245


Kod
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  kolko_krzyzyk.py
 
class Board():
   def __init__(self):
       self.counter_move = 0
       self.board = [["#" for _ in range(3)] for _ in range(3)]
       self.prev_move = []
       self.won = None
 
   def undo(self):
       if self.prev_move:
           dimensionX = self.prev_move[-1][0]
           dimensionY = self.prev_move[-1][1]
           self.board[dimensionY][dimensionX] = "#"
           self.prev_move.pop()
           self.counter_move -= 1
           return True
       return False
 
   def move(self, field):
       field -= 1
       selected = (field%3, field//3)
       if selected not in self.prev_move:
           self.prev_move.append(selected)
           self.board[selected[1]][selected[0]] = "o" if self.counter_move % 2 else "x"
           self.counter_move += 1
           return True
       return False
 
   def check_win(self):
       won_x = ['x', 'x', 'x']
       won_y = ['o', 'o', 'o']
       rotated_board = [[new[i] for new in self.board[::-1]] for i in range(3)]
       cross_lines = [[self.board[it][it] for it in range(3)], [rotated_board[itm][itm] for itm in range(3)]]
       #Check after move x
       if self.counter_move % 2:
           if won_x in self.board or won_x in rotated_board or won_x in cross_lines:
               self.won = "X won"
               return True
       #Check after move o
       else:
           if won_y in self.board or won_y in rotated_board or won_y in cross_lines:
               self.won = "O won"
               return True
       #If some fields are empty, continue the game
       for line in self.board:
           if "#" in line:
               return False
       #Otherwise, end with remis statement
       else:
           self.won = "Remis"
           return True
 
   def some_win(self):
       return self.won
 
   def show_board(self):
       for line in self.board:
           print(line)
 
 
class Game():
   def __init__(self):
       self.table = Board()
 
   def run(self):
       while True:
           #Show board
           self.table.show_board()
 
           #Catch moves
           while True:
               move = input("Insert position: ")
               if move != "c" and self.table.move(int(move)):
                   break
               elif move == "c" and self.table.undo():
                   break
               else:
                   print("Wrong move, repeat!")
 
           #Check winner or remis
           if self.table.check_win():
               break
 
       #Print result
       self.table.show_board()
       print(self.table.some_win())
 
 
 
 
def main(args):
   game = Game()
   game.run()
   return 0
 
if __name__ == '__main__':
   import sys
   sys.exit(main(sys.argv))
 
W sumie jakieś pół godziny, jedyne co trzeba tam poprawić to walidację. Trochę inne podejście zastosowałem, by przechowywać maksymalnie dwie tablice przechowujące po trzy tablice, i jedną 'cross' aby przechowywać dwie tablice.
Zamiast dla każdego kroki, zapisywać wszystkie stany tablic, kroki są zapisane w krotkach.

Ogólnie wydaje mi się że wszystko działa z cofaniem, może to nie odpowiedź na twoje pytanie, ale oddaję do analizy, może się przyda :d.
Na tej podstawie też łatwo picklować, bez wymyślnych struktur.
Zapisane

Python 3.5.2 / Mint
Strony: [1]   Do góry
Drukuj
Skocz do:  

© 2007 - 2018 Polish Python Coders Group
Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines | Theme by PixelSlot