Advertisement
Guest User

Untitled

a guest
Jan 23rd, 2019
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.90 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import random
  4. import sys
  5. import gi
  6. import argparse
  7. gi.require_version('Gtk', '3.0')
  8. from gi.repository import Gtk
  9.  
  10.  
  11. # kody pol - nie zmieniac
  12. HWHITE = 0
  13. HBLACK = 1
  14. HBLOCKED = 2
  15. HFREE = 3
  16.  
  17. # obrazki
  18. HIMAGES = ("bialy.png", "czarny.png", "zablokowany.png", "pusty.png")
  19.  
  20. # kody literowe dla pol
  21. CHARCODES = "bcX."
  22.  
  23.  
  24. class Plansza:
  25. """
  26. Prosta klasa reprezentujaca szachownice z pionkami
  27. """
  28.  
  29. def __init__(self, *args):
  30. """
  31. Zrob plansze na listach
  32. @TODO: zaimplementowac sprawdzanie poprawnosci napisow
  33. """
  34. self.t = [[CHARCODES.find(p) for p in s] for s in args]
  35.  
  36. def move(self, skad, dokad):
  37. """
  38. Przestawia pionek
  39. zwraca True gdy sukces
  40. """
  41. if not self.t[skad[0]][skad[1]] in [HBLACK, HWHITE]:
  42. return False
  43.  
  44. if self.t[dokad[0]][dokad[1]] != HFREE:
  45. return False
  46.  
  47. # wstaw stare na nowe
  48. self.t[dokad[0]][dokad[1]] = self.t[skad[0]][skad[1]]
  49.  
  50. # zwolnij stare
  51. self.t[skad[0]][skad[1]] = HFREE
  52. return True
  53.  
  54. def at(self, *args):
  55. """
  56. zwraca element po indeksem planszy
  57. argumentem moze byc krotka (para) lub dwie wartosci
  58. """
  59. if len(args) > 1:
  60. return self.t[args[0]][args[1]]
  61. return self.t[args[0][0]][args[0][1]]
  62.  
  63. def N(self):
  64. """
  65. liczba wierszy
  66. """
  67. return len(self.t)
  68.  
  69. def K(self):
  70. """
  71. liczba kolumn
  72. """
  73. return len(self.t[0])
  74.  
  75.  
  76. class Halma:
  77. """
  78. Klasa reprezentujaca interfejs gry, korzysta z dostarczanych
  79. funkcji by przeprowadzic rozgrywke
  80. """
  81.  
  82. def close_application(self, widget, event, data=None):
  83. Gtk.main_quit()
  84. return False
  85.  
  86. def move(self, skad, dokad):
  87.  
  88. # czy ruch zgodny z zasadami?
  89. if not dobryruch(self.plansza, skad, dokad, self.gracz):
  90. print("Ruch niezgodny z zasadami gry!")
  91. return False
  92.  
  93. # pionek gracza musi tam stac
  94. if self.gracz != self.plansza.at(skad):
  95. return False
  96.  
  97. # przenies na planszy
  98. if not self.plansza.move(skad, dokad):
  99. return False
  100.  
  101. # narysuj obrazki
  102. image = Gtk.Image()
  103. image.set_from_file(HIMAGES[HFREE])
  104. image.show()
  105. self.buttons[skad[0]][skad[1]].set_image(image)
  106.  
  107. image = Gtk.Image()
  108. image.set_from_file(HIMAGES[self.gracz])
  109. image.show()
  110. self.buttons[dokad[0]][dokad[1]].set_image(image)
  111.  
  112. return True
  113.  
  114. def noninteractivemove(self):
  115. """
  116. Ruch komputera z uzyciem funkcji ruch
  117. """
  118. if not self.ruchy[self.gracz]:
  119. return None
  120.  
  121. (skad, dokad) = self.ruchy[self.gracz](self.plansza, self.gracz)
  122. if not self.move(skad, dokad):
  123. raise Exception(
  124. "Ooops - funkcja postaw zle dziala dla gracza nr %d" % self.gracz)
  125. self.gracz = (self.gracz+1) % 2
  126.  
  127. return self.endofgame()
  128.  
  129. def endofgame(self):
  130. """
  131. Sprawdz czy koniec gry
  132. """
  133. if stanrozgrywki(self.plansza) >= 0:
  134. """
  135. @TODO: ladnie wypisac wynik w zaleznosci od wyniku stanrozgrywki
  136. """
  137. print("Koniec gry!")
  138. if stanrozgrywki(self.plansza) == 0:
  139. print("Biali wygrali!")
  140. if stanrozgrywki(self.plansza) == 1:
  141. print("Czarni wygrali!")
  142. return True
  143.  
  144. return False
  145.  
  146. def buttonpressed(self, widget, data=None):
  147.  
  148. print("Kliknieto", data)
  149.  
  150. # sprawdz czy koniec
  151. if stanrozgrywki(self.plansza) >= 0:
  152. print("Gra juz dawno zakonczona!")
  153. return
  154.  
  155. # gdy nieinteraktywnie
  156. if self.ruchy[self.gracz]:
  157. self.noninteractivemove()
  158. return
  159.  
  160. if not self.click:
  161. # kliknieto pierwszy raz
  162. if self.plansza.at(data) != self.gracz:
  163. print("Tam nie stoi Twoj pionek - sprobuj jeszcze raz!")
  164. print("Teraz ruch gracza %s" % CHARCODES[self.gracz])
  165. else:
  166. # zapamietaj pozycje
  167. self.click = data
  168. return
  169.  
  170. # jestemy tutaj to oznacza, ze kliknieto drugi raz
  171. # teraz sprobuj przemiescic pionek
  172.  
  173. # interaktywna gra
  174. if not self.move(self.click, data):
  175. print("Zle klikniecia - zacznij jeszcze raz")
  176. print("Teraz ruch gracza %s" % CHARCODES[self.gracz])
  177. self.click = None
  178. return
  179.  
  180. self.click = None
  181.  
  182. # sprawdz stan rozgrywki
  183. if self.endofgame():
  184. return
  185.  
  186. # kolej na nastepnego gracza
  187. # uwaga wazne jest by HWHITE, HBLACK byly 0 i 1
  188. self.gracz = (self.gracz+1) % 2
  189.  
  190. # drugi gracz - rusza sie tylko gdy nieinteraktywnie
  191. self.noninteractivemove()
  192.  
  193. # sprawdz stan rozgrywki
  194. self.endofgame()
  195.  
  196. def __init__(self, plansza, fpostawb=None, fpostawc=None):
  197. """
  198. Konstruktor dla okienka Halmy
  199.  
  200. plansza - plansza
  201. fpostawb - funkcja do stawiania bialych - jesli None to interaktywnie
  202. fpostawb - funkcja do stawiania czarnych - jesli None to interaktywnie
  203. """
  204.  
  205. self.click = None
  206. self.ruchy = [fpostawb, fpostawc]
  207.  
  208. # przyjmuje wartosci HWHITE, HBLACK
  209. # zaczyna bialy
  210. self.gracz = HWHITE
  211.  
  212. self.plansza = plansza
  213.  
  214. # zrob okno
  215. window = Gtk.Window()
  216. window.connect("delete_event", self.close_application)
  217. window.set_border_width(10)
  218.  
  219. table = Gtk.Table(self.plansza.N(), self.plansza.K(), True)
  220. window.add(table)
  221.  
  222. self.buttons = [] # do zapamietania przyciskow
  223.  
  224. # zrob przyciski na oknie reprezentujace pola
  225. for i in range(self.plansza.N()):
  226. self.buttons.append([])
  227. for j in range(self.plansza.K()):
  228. image = Gtk.Image()
  229. image.set_from_file(HIMAGES[plansza.at(i, j)])
  230. image.show()
  231.  
  232. button = Gtk.Button()
  233. button.add(image)
  234. button.show()
  235. table.attach(button, j, j+1, i, i+1)
  236.  
  237. # zarejestruj zdarzenia klikniecia
  238. button.connect("clicked", self.buttonpressed, (i, j))
  239. self.buttons[i].append(button)
  240.  
  241. table.show()
  242. window.show()
  243.  
  244.  
  245. def main():
  246. Gtk.main()
  247. return 0
  248.  
  249.  
  250. def ruchlosowy(plansza, gracz):
  251. """
  252. Przykladowa funkcja typu ruch - ale tylko losowa
  253. Uwaga - oczywiscie generuje takze nieprawidlowe ruchy
  254. @TODO: poprawic by zwracane byly tylko dobre ruchy - gotowe
  255. """
  256. def znajdz(co):
  257. return [(i, j) for i in range(plansza.N()) for j in range(plansza.K())
  258. if plansza.at(i, j) == co]
  259. while True:
  260. start = random.choice(znajdz(gracz))
  261. cel = random.choice(znajdz(HFREE))
  262. if dobryruch(plansza, start, cel, gracz):
  263. return(start, cel)
  264.  
  265. # return ( random.choice(znajdz(gracz)), random.choice(znajdz(HFREE)))
  266.  
  267.  
  268. def planszalosowa(N, K, M):
  269. """
  270. @TODO: zaimplementowac planszalosowa(N,K,M) - gotowe
  271. """
  272. # Pusta plansza
  273. board = ['.' * K for n in range(N)]
  274. if N < 3 or K < 3:
  275. raise Exception("Plansza jest za mala!")
  276. if M < 2:
  277. raise Exception("Za malo pionkow!")
  278. if M > N or M > K:
  279. raise Exception("Za duzo pionkow!")
  280. # Ukladamy pionki
  281. for m in range(M):
  282. # Ukladamy czarne od dolu i odwracamy rzad, by byly po dobrej stronie
  283. board[N-m-1] = board[N-m-1].replace('.', 'c', M-m-1)[::-1]
  284. for m in range(M):
  285. # Ukladamy biale od gory
  286. board[m] = board[m].replace('.', 'b', M-m-1)
  287. for l in range(random.randint(0, 3 * K)):
  288. R = random.randint(0, N-1)
  289. board[R] = list(board[R])
  290. r = random.randint(0, K-1)
  291. if board[R][r] == '.':
  292. board[R][r] = 'X'
  293. board[R] = ''.join(board[R])
  294. return Plansza(*board)
  295.  
  296.  
  297. def stanrozgrywki(plansza):
  298. """
  299. @TODO: zaimplementowac stanrozgrywki(plansza):
  300. """
  301. N = plansza.N()
  302. K = plansza.K()
  303. bwin, cwin = True, True
  304. count = 0
  305. for n in range(N):
  306. for k in range(K):
  307. if plansza.at(n, k) == 0 or plansza.at(n, k) == 1:
  308. count += 1
  309. M = int((1 + ((1 + 4 * count) ** 0.5))/2)
  310.  
  311. for x in range(M-1):
  312. for b in range(M-x-1):
  313. if plansza.at(x, b) != 1:
  314. cwin = False
  315. for m in range(M):
  316. for a in range(M-m-1):
  317. if plansza.at(N-m-1, K-a-1) != 0:
  318. bwin = False
  319.  
  320. if bwin:
  321. return HWHITE
  322. if cwin:
  323. return HBLACK
  324. elif count % 2 != 0 or count == 0:
  325. return Exception("Bledna plansza")
  326. return -1
  327.  
  328.  
  329. def ruch(plansza, gracz): # plansza, HBLACK/HWHITE
  330. """
  331. @TODO: zaimplementowac ruch(plansza, gracz)
  332. """
  333. def znajdz(co):
  334. return [(i, j) for i in range(plansza.N()) for j in range(plansza.K())
  335. if plansza.at(i, j) == co]
  336.  
  337. if gracz == HWHITE:
  338. best = ((0, 0), (0, 0), float("inf"))
  339. else:
  340. best = ((0, 0), (0, 0), -float("inf"))
  341. for pion in znajdz(gracz):
  342. for move in znajdz(HFREE):
  343. if dobryruch(plansza, pion, move, gracz):
  344. plansza.move(pion, move)
  345. if stanrozgrywki(plansza) == gracz:
  346. plansza.move(move, pion)
  347. return (pion, move)
  348. plansza.move(move, pion)
  349. roznica = (pion[0]+1 * pion[1]+1) - (move[0]+1 * move[1]+1)
  350. if gracz == HWHITE:
  351. if roznica < best[2]:
  352. best = (pion, move, roznica)
  353. else:
  354. if roznica > best[2]:
  355. best = (pion, move, roznica)
  356. return (best[0], best[1])
  357.  
  358.  
  359. def dobryruch(plansza, skad, dokad, gracz):
  360. """
  361. Sprawdza czy ruch pionkiem z pola skad do dokad dla gracza gracz
  362. jest zgodny z zasadami gry
  363. @TODO: zaimplementowac dobryruch(plansza, skad, dokad, gracz) - gotowe
  364. """
  365. # print(skad, dokad)
  366. if (skad[0]-dokad[0] == 1 or skad[0]-dokad[0] == 0 or
  367. skad[0]-dokad[0] == -1) and\
  368. (skad[1]-dokad[1] == 1 or skad[1]-dokad[1] == 0 or
  369. skad[1]-dokad[1] == -1):
  370. return True
  371. else:
  372. vertical = dokad[0] - skad[0] # pozytywne w dol
  373. horizontal = dokad[1] - skad[1] # pozytywne w prawo
  374. if vertical < 0:
  375. if skad[0] != 0:
  376. if plansza.at((skad[0] - 1, skad[1])) != HFREE:
  377. if dobryruch(plansza, (skad[0] - 1, skad[1]), dokad, gracz):
  378. return True
  379. if vertical > 0:
  380. if skad[0] != plansza.N()-1:
  381. if plansza.at((skad[0] + 1, skad[1])) != HFREE:
  382. if dobryruch(plansza, (skad[0] + 1, skad[1]), dokad, gracz):
  383. return True
  384. if horizontal < 0:
  385. if skad[1] != 0:
  386. if plansza.at((skad[0], skad[1] - 1)) != HFREE:
  387. if dobryruch(plansza, (skad[0], skad[1] - 1), dokad, gracz):
  388. return True
  389. if horizontal > 0:
  390. if skad[1] != plansza.K()-1:
  391. if plansza.at((skad[0], skad[1] + 1)) != HFREE:
  392. if dobryruch(plansza, (skad[0], skad[1] + 1), dokad, gracz):
  393. return True
  394. if vertical >= 0 and horizontal >= 0:
  395. if skad[0] != plansza.N()-1 and skad[1] != plansza.K()-1:
  396. if plansza.at(((skad[0] + 1), (skad[1] + 1))) != HFREE:
  397. if dobryruch(plansza, ((skad[0] + 1), (skad[1] + 1)), dokad, gracz):
  398. return True
  399. if vertical >= 0 and horizontal <= 0:
  400. if skad[0] != plansza.N()-1 and skad[1] != 0:
  401. if plansza.at(((skad[0] + 1), (skad[1] - 1))) != HFREE:
  402. if dobryruch(plansza, ((skad[0] + 1), (skad[1] - 1)), dokad, gracz):
  403. return True
  404. if vertical <= 0 and horizontal >= 0:
  405. if skad[0] != 0 and skad[1] != plansza.K()-1:
  406. if plansza.at(((skad[0] - 1), (skad[1] + 1))) != HFREE:
  407. if dobryruch(plansza, (((skad[0] - 1), (skad[1] + 1))), dokad, gracz):
  408. return True
  409. if vertical <= 0 and horizontal <= 0:
  410. if skad[0] != 0 and skad[1] != 0:
  411. if plansza.at(((skad[0] - 1), (skad[1] - 1))) != HFREE:
  412. if dobryruch(plansza, ((skad[0] - 1), (skad[1] - 1)), dokad, gracz):
  413. return True
  414. return False
  415.  
  416.  
  417. def check_arguments():
  418. # Jak uzywac argparse: https://stackoverflow.com/questions/20063/whats-the-best-way-to-parse-command-line-arguments
  419. parser = argparse.ArgumentParser(description='Przyklad uruchomienia skryptu: \npython halma_alicja_gromek.py --losowa_plansza 1 \
  420. --szer 10 --wys 10 --ilosc_pionkow 3 --biale gracz --czarne ruch')
  421. #argumenty
  422. parser.add_argument("--losowa_plansza", help='''
  423. 1 jesli chcemy losowac plansze, wtedy wymagane jest podanie parametrow:
  424. --szer, --wys, --ilosc_pionkow, --biale, --czarne,
  425.  
  426. 0 jesli chcesz samemu stworzyc plansze, wtedy podajemy parametry:
  427. --wyglad, --biale, --czarne''', type=int, nargs='?')
  428. #argumenty dla losowej planszy
  429. parser.add_argument("--szer", help="szerokosc planszy - dowolna liczba wieksza od 2", type=int, nargs='?')
  430. parser.add_argument("--wys", help="wysokosc planszy - downolna liczba wieksza od 2", type=int, nargs='?')
  431. 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='?')
  432. parser.add_argument("--biale", help="kontrolujacy biale pionki - ruch dla gracza komputerowego, ruchlosowy dla losowych ruchow, gracz dla zywego gracza", type=str, nargs='?')
  433. parser.add_argument("--czarne", help="kontrolujacy czarne pionki - tak samo jak w przypadku bialych", type=str, nargs='?')
  434.  
  435. #argumenty dla definiowanej planszy
  436. 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. \
  437. b to pionek bialy, c to pionek czarny, . to puste pole, a X to zablokowane pole.", type=str, nargs='?')
  438.  
  439. args = parser.parse_args()
  440.  
  441. #przypisanie funkcji parametrom
  442. if args.biale == "ruchlosowy":
  443. args.biale = ruchlosowy
  444. if args.biale == "ruch":
  445. args.biale = ruch
  446. if args.czarne == "ruchlosowy":
  447. args.czarne = ruchlosowy
  448. if args.czarne == "ruch":
  449. args.czarne = ruch
  450.  
  451. if args.losowa_plansza == 1:
  452. if all([args.szer, args.wys, args.ilosc_pionkow, args.biale, args.czarne]):
  453. if args.czarne == "gracz":
  454. args.czarne = None
  455. if args.biale == "gracz":
  456. args.biale = None
  457. Halma(planszalosowa(args.szer, args.wys, args.ilosc_pionkow), args.biale, args.czarne)
  458. else:
  459. print("Nie podales wszystkich parametrow! Wpisz --help aby uzyskac informacje")
  460. exit()
  461. elif args.losowa_plansza == 0:
  462. if all([args.wyglad, args.biale, args.czarne]) in args:
  463. if args.biale == "gracz":
  464. args.biale == None
  465. if args.czarne == "gracz":
  466. args.czarne == None
  467. Halma(Plansza(*args.wyglad.split(",")), args.biale, args.czarne)
  468. else:
  469. exit()
  470. else:
  471. print("Brak parametru --losowa_plansza!!!")
  472. exit()
  473.  
  474. if __name__ == "__main__":
  475. check_arguments()
  476. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement