Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- import random
- import sys
- import gi
- import argparse
- gi.require_version('Gtk', '3.0')
- from gi.repository import Gtk
- # kody pol - nie zmieniac
- HWHITE = 0
- HBLACK = 1
- HBLOCKED = 2
- HFREE = 3
- # obrazki
- HIMAGES = ("bialy.png", "czarny.png", "zablokowany.png", "pusty.png")
- # kody literowe dla pol
- CHARCODES = "bcX."
- class Plansza:
- """
- Prosta klasa reprezentujaca szachownice z pionkami
- """
- def __init__(self, *args):
- """
- Zrob plansze na listach
- @TODO: zaimplementowac sprawdzanie poprawnosci napisow
- """
- self.t = [[CHARCODES.find(p) for p in s] for s in args]
- def move(self, skad, dokad):
- """
- Przestawia pionek
- zwraca True gdy sukces
- """
- if not self.t[skad[0]][skad[1]] in [HBLACK, HWHITE]:
- return False
- if self.t[dokad[0]][dokad[1]] != HFREE:
- return False
- # wstaw stare na nowe
- self.t[dokad[0]][dokad[1]] = self.t[skad[0]][skad[1]]
- # zwolnij stare
- self.t[skad[0]][skad[1]] = HFREE
- return True
- def at(self, *args):
- """
- zwraca element po indeksem planszy
- argumentem moze byc krotka (para) lub dwie wartosci
- """
- if len(args) > 1:
- return self.t[args[0]][args[1]]
- return self.t[args[0][0]][args[0][1]]
- def N(self):
- """
- liczba wierszy
- """
- return len(self.t)
- def K(self):
- """
- liczba kolumn
- """
- return len(self.t[0])
- class Halma:
- """
- Klasa reprezentujaca interfejs gry, korzysta z dostarczanych
- funkcji by przeprowadzic rozgrywke
- """
- def close_application(self, widget, event, data=None):
- Gtk.main_quit()
- return False
- def move(self, skad, dokad):
- # czy ruch zgodny z zasadami?
- if not dobryruch(self.plansza, skad, dokad, self.gracz):
- print("Ruch niezgodny z zasadami gry!")
- return False
- # pionek gracza musi tam stac
- if self.gracz != self.plansza.at(skad):
- return False
- # przenies na planszy
- if not self.plansza.move(skad, dokad):
- return False
- # narysuj obrazki
- image = Gtk.Image()
- image.set_from_file(HIMAGES[HFREE])
- image.show()
- self.buttons[skad[0]][skad[1]].set_image(image)
- image = Gtk.Image()
- image.set_from_file(HIMAGES[self.gracz])
- image.show()
- self.buttons[dokad[0]][dokad[1]].set_image(image)
- return True
- def noninteractivemove(self):
- """
- Ruch komputera z uzyciem funkcji ruch
- """
- if not self.ruchy[self.gracz]:
- return None
- (skad, dokad) = self.ruchy[self.gracz](self.plansza, self.gracz)
- if not self.move(skad, dokad):
- raise Exception(
- "Ooops - funkcja postaw zle dziala dla gracza nr %d" % self.gracz)
- self.gracz = (self.gracz+1) % 2
- return self.endofgame()
- def endofgame(self):
- """
- Sprawdz czy koniec gry
- """
- if stanrozgrywki(self.plansza) >= 0:
- """
- @TODO: ladnie wypisac wynik w zaleznosci od wyniku stanrozgrywki
- """
- print("Koniec gry!")
- if stanrozgrywki(self.plansza) == 0:
- print("Biali wygrali!")
- if stanrozgrywki(self.plansza) == 1:
- print("Czarni wygrali!")
- return True
- return False
- def buttonpressed(self, widget, data=None):
- print("Kliknieto", data)
- # sprawdz czy koniec
- if stanrozgrywki(self.plansza) >= 0:
- print("Gra juz dawno zakonczona!")
- return
- # gdy nieinteraktywnie
- if self.ruchy[self.gracz]:
- self.noninteractivemove()
- return
- if not self.click:
- # kliknieto pierwszy raz
- if self.plansza.at(data) != self.gracz:
- print("Tam nie stoi Twoj pionek - sprobuj jeszcze raz!")
- print("Teraz ruch gracza %s" % CHARCODES[self.gracz])
- else:
- # zapamietaj pozycje
- self.click = data
- return
- # jestemy tutaj to oznacza, ze kliknieto drugi raz
- # teraz sprobuj przemiescic pionek
- # interaktywna gra
- if not self.move(self.click, data):
- print("Zle klikniecia - zacznij jeszcze raz")
- print("Teraz ruch gracza %s" % CHARCODES[self.gracz])
- self.click = None
- return
- self.click = None
- # sprawdz stan rozgrywki
- if self.endofgame():
- return
- # kolej na nastepnego gracza
- # uwaga wazne jest by HWHITE, HBLACK byly 0 i 1
- self.gracz = (self.gracz+1) % 2
- # drugi gracz - rusza sie tylko gdy nieinteraktywnie
- self.noninteractivemove()
- # sprawdz stan rozgrywki
- self.endofgame()
- def __init__(self, plansza, fpostawb=None, fpostawc=None):
- """
- Konstruktor dla okienka Halmy
- plansza - plansza
- fpostawb - funkcja do stawiania bialych - jesli None to interaktywnie
- fpostawb - funkcja do stawiania czarnych - jesli None to interaktywnie
- """
- self.click = None
- self.ruchy = [fpostawb, fpostawc]
- # przyjmuje wartosci HWHITE, HBLACK
- # zaczyna bialy
- self.gracz = HWHITE
- self.plansza = plansza
- # zrob okno
- window = Gtk.Window()
- window.connect("delete_event", self.close_application)
- window.set_border_width(10)
- table = Gtk.Table(self.plansza.N(), self.plansza.K(), True)
- window.add(table)
- self.buttons = [] # do zapamietania przyciskow
- # zrob przyciski na oknie reprezentujace pola
- for i in range(self.plansza.N()):
- self.buttons.append([])
- for j in range(self.plansza.K()):
- image = Gtk.Image()
- image.set_from_file(HIMAGES[plansza.at(i, j)])
- image.show()
- button = Gtk.Button()
- button.add(image)
- button.show()
- table.attach(button, j, j+1, i, i+1)
- # zarejestruj zdarzenia klikniecia
- button.connect("clicked", self.buttonpressed, (i, j))
- self.buttons[i].append(button)
- table.show()
- window.show()
- def main():
- Gtk.main()
- return 0
- def ruchlosowy(plansza, gracz):
- """
- Przykladowa funkcja typu ruch - ale tylko losowa
- Uwaga - oczywiscie generuje takze nieprawidlowe ruchy
- @TODO: poprawic by zwracane byly tylko dobre ruchy - gotowe
- """
- def znajdz(co):
- return [(i, j) for i in range(plansza.N()) for j in range(plansza.K())
- if plansza.at(i, j) == co]
- while True:
- start = random.choice(znajdz(gracz))
- cel = random.choice(znajdz(HFREE))
- if dobryruch(plansza, start, cel, gracz):
- return(start, cel)
- # return ( random.choice(znajdz(gracz)), random.choice(znajdz(HFREE)))
- def planszalosowa(N, K, M):
- """
- @TODO: zaimplementowac planszalosowa(N,K,M) - gotowe
- """
- # Pusta plansza
- board = ['.' * K for n in range(N)]
- if N < 3 or K < 3:
- raise Exception("Plansza jest za mala!")
- if M < 2:
- raise Exception("Za malo pionkow!")
- if M > N or M > K:
- raise Exception("Za duzo pionkow!")
- # Ukladamy pionki
- for m in range(M):
- # Ukladamy czarne od dolu i odwracamy rzad, by byly po dobrej stronie
- board[N-m-1] = board[N-m-1].replace('.', 'c', M-m-1)[::-1]
- for m in range(M):
- # Ukladamy biale od gory
- board[m] = board[m].replace('.', 'b', M-m-1)
- for l in range(random.randint(0, 3 * K)):
- R = random.randint(0, N-1)
- board[R] = list(board[R])
- r = random.randint(0, K-1)
- if board[R][r] == '.':
- board[R][r] = 'X'
- board[R] = ''.join(board[R])
- return Plansza(*board)
- def stanrozgrywki(plansza):
- """
- @TODO: zaimplementowac stanrozgrywki(plansza):
- """
- N = plansza.N()
- K = plansza.K()
- bwin, cwin = True, True
- count = 0
- for n in range(N):
- for k in range(K):
- if plansza.at(n, k) == 0 or plansza.at(n, k) == 1:
- count += 1
- M = int((1 + ((1 + 4 * count) ** 0.5))/2)
- for x in range(M-1):
- for b in range(M-x-1):
- if plansza.at(x, b) != 1:
- cwin = False
- for m in range(M):
- for a in range(M-m-1):
- if plansza.at(N-m-1, K-a-1) != 0:
- bwin = False
- if bwin:
- return HWHITE
- if cwin:
- return HBLACK
- elif count % 2 != 0 or count == 0:
- return Exception("Bledna plansza")
- return -1
- def ruch(plansza, gracz): # plansza, HBLACK/HWHITE
- """
- @TODO: zaimplementowac ruch(plansza, gracz)
- """
- def znajdz(co):
- return [(i, j) for i in range(plansza.N()) for j in range(plansza.K())
- if plansza.at(i, j) == co]
- if gracz == HWHITE:
- best = ((0, 0), (0, 0), float("inf"))
- else:
- best = ((0, 0), (0, 0), -float("inf"))
- for pion in znajdz(gracz):
- for move in znajdz(HFREE):
- if dobryruch(plansza, pion, move, gracz):
- plansza.move(pion, move)
- if stanrozgrywki(plansza) == gracz:
- plansza.move(move, pion)
- return (pion, move)
- plansza.move(move, pion)
- roznica = (pion[0]+1 * pion[1]+1) - (move[0]+1 * move[1]+1)
- if gracz == HWHITE:
- if roznica < best[2]:
- best = (pion, move, roznica)
- else:
- if roznica > best[2]:
- best = (pion, move, roznica)
- return (best[0], best[1])
- def dobryruch(plansza, skad, dokad, gracz):
- """
- Sprawdza czy ruch pionkiem z pola skad do dokad dla gracza gracz
- jest zgodny z zasadami gry
- @TODO: zaimplementowac dobryruch(plansza, skad, dokad, gracz) - gotowe
- """
- # print(skad, dokad)
- if (skad[0]-dokad[0] == 1 or skad[0]-dokad[0] == 0 or
- skad[0]-dokad[0] == -1) and\
- (skad[1]-dokad[1] == 1 or skad[1]-dokad[1] == 0 or
- skad[1]-dokad[1] == -1):
- return True
- else:
- vertical = dokad[0] - skad[0] # pozytywne w dol
- horizontal = dokad[1] - skad[1] # pozytywne w prawo
- if vertical < 0:
- if skad[0] != 0:
- if plansza.at((skad[0] - 1, skad[1])) != HFREE:
- if dobryruch(plansza, (skad[0] - 1, skad[1]), dokad, gracz):
- return True
- if vertical > 0:
- if skad[0] != plansza.N()-1:
- if plansza.at((skad[0] + 1, skad[1])) != HFREE:
- if dobryruch(plansza, (skad[0] + 1, skad[1]), dokad, gracz):
- return True
- if horizontal < 0:
- if skad[1] != 0:
- if plansza.at((skad[0], skad[1] - 1)) != HFREE:
- if dobryruch(plansza, (skad[0], skad[1] - 1), dokad, gracz):
- return True
- if horizontal > 0:
- if skad[1] != plansza.K()-1:
- if plansza.at((skad[0], skad[1] + 1)) != HFREE:
- if dobryruch(plansza, (skad[0], skad[1] + 1), dokad, gracz):
- return True
- if vertical >= 0 and horizontal >= 0:
- if skad[0] != plansza.N()-1 and skad[1] != plansza.K()-1:
- if plansza.at(((skad[0] + 1), (skad[1] + 1))) != HFREE:
- if dobryruch(plansza, ((skad[0] + 1), (skad[1] + 1)), dokad, gracz):
- return True
- if vertical >= 0 and horizontal <= 0:
- if skad[0] != plansza.N()-1 and skad[1] != 0:
- if plansza.at(((skad[0] + 1), (skad[1] - 1))) != HFREE:
- if dobryruch(plansza, ((skad[0] + 1), (skad[1] - 1)), dokad, gracz):
- return True
- if vertical <= 0 and horizontal >= 0:
- if skad[0] != 0 and skad[1] != plansza.K()-1:
- if plansza.at(((skad[0] - 1), (skad[1] + 1))) != HFREE:
- if dobryruch(plansza, (((skad[0] - 1), (skad[1] + 1))), dokad, gracz):
- return True
- if vertical <= 0 and horizontal <= 0:
- if skad[0] != 0 and skad[1] != 0:
- if plansza.at(((skad[0] - 1), (skad[1] - 1))) != HFREE:
- if dobryruch(plansza, ((skad[0] - 1), (skad[1] - 1)), dokad, gracz):
- return True
- return False
- def check_arguments():
- # Jak uzywac argparse: https://stackoverflow.com/questions/20063/whats-the-best-way-to-parse-command-line-arguments
- parser = argparse.ArgumentParser(description='Przyklad uruchomienia skryptu: \npython halma_alicja_gromek.py --losowa_plansza 1 \
- --szer 10 --wys 10 --ilosc_pionkow 3 --biale gracz --czarne ruch')
- #argumenty
- parser.add_argument("--losowa_plansza", help='''
- 1 jesli chcemy losowac plansze, wtedy wymagane jest podanie parametrow:
- --szer, --wys, --ilosc_pionkow, --biale, --czarne,
- 0 jesli chcesz samemu stworzyc plansze, wtedy podajemy parametry:
- --wyglad, --biale, --czarne''', type=int, nargs='?')
- #argumenty dla losowej planszy
- parser.add_argument("--szer", help="szerokosc planszy - dowolna liczba wieksza od 2", type=int, nargs='?')
- parser.add_argument("--wys", help="wysokosc planszy - downolna liczba wieksza od 2", type=int, nargs='?')
- parser.add_argument("--ilosc_pionkow", help="ilosc pionkow - dlugosc ramienia trojkata tworzocego pionki, liczba wieksza od 1 i mniejsza lub rowna od mniejszemu bokowi planszy", type=int, nargs='?')
- parser.add_argument("--biale", help="kontrolujacy biale pionki - ruch dla gracza komputerowego, ruchlosowy dla losowych ruchow, gracz dla zywego gracza", type=str, nargs='?')
- parser.add_argument("--czarne", help="kontrolujacy czarne pionki - tak samo jak w przypadku bialych", type=str, nargs='?')
- #argumenty dla definiowanej planszy
- parser.add_argument("--wyglad", help="wyglad planszy w formacie bbb,...,XXX,ccc, gdzie kazda litera odpowiada jednemu polu na planszy, a przecinek oznacza przejscie do nowego rzedu. \
- b to pionek bialy, c to pionek czarny, . to puste pole, a X to zablokowane pole.", type=str, nargs='?')
- args = parser.parse_args()
- #przypisanie funkcji parametrom
- if args.biale == "ruchlosowy":
- args.biale = ruchlosowy
- if args.biale == "ruch":
- args.biale = ruch
- if args.czarne == "ruchlosowy":
- args.czarne = ruchlosowy
- if args.czarne == "ruch":
- args.czarne = ruch
- if args.losowa_plansza == 1:
- if all([args.szer, args.wys, args.ilosc_pionkow, args.biale, args.czarne]):
- if args.czarne == "gracz":
- args.czarne = None
- if args.biale == "gracz":
- args.biale = None
- Halma(planszalosowa(args.szer, args.wys, args.ilosc_pionkow), args.biale, args.czarne)
- else:
- print("Nie podales wszystkich parametrow! Wpisz --help aby uzyskac informacje")
- exit()
- elif args.losowa_plansza == 0:
- if all([args.wyglad, args.biale, args.czarne]) in args:
- if args.biale == "gracz":
- args.biale == None
- if args.czarne == "gracz":
- args.czarne == None
- Halma(Plansza(*args.wyglad.split(",")), args.biale, args.czarne)
- else:
- exit()
- else:
- print("Brak parametru --losowa_plansza!!!")
- exit()
- if __name__ == "__main__":
- check_arguments()
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement