Semestrální práce spočívá ve vytvoření funkčního hráče (programu) pro hru inspirovanou Battle of LITS . LITS je desková hra pro dva hráče, ve které se hraje s kameny různých tvarů a barev. Na hrací desce jsou značky pro oba hráče (“x” a “o”), cílem hráče je nechat co nejvíce svých značek nepokrytých a naopak pokrýt co nejvíce značek patřících protihráči. Obtížnost hry spočívá v pravidlech pro umisťování kamenů (viz dále). Naše hra pro předmět ALP se mírně liší od oficiálnách pravidel LITSu. Platná jsou pouze pravidla uvedená na této stránce.
Finalní skóre je 7 vs. 3 (7 koleček nepokrytých, 3 křížky nepokryté). Vyhrává hráč 1, který hraje “za kolečka”. }
Balíček obsahuje třídy pro vyzkoušení hry na vašem počítači:
V případě, že nastanou změny v zadání nebo bude např. upraveno/rozšířeno herní rozhraní, budou změny uvedeny v této sekci.
self.algorithm
(podle toho poznáte, kterou verzi vašeho hráče jsme natáhli do turnaje). Proměnná self.tournament
je v turnaji nastavena na True.
import sys import random import copy import base from draw import Drawer class Player(base.BasePlayer): def __init__(self, name, board, marks, stones, player): """ constructor of Player. Place you variables here with prefix 'self' -> e.g. 'self.myVariable' """ base.BasePlayer.__init__(self, name, board, marks, stones, player) #do not change this line!! self.algorithm = "my great method" #name of your method. Will be used in tournament mode def move(self): """ return [ stoneIdx, [ stonePosition] ] stoneIdx .. integer .. index of stone to self.freeStones [stonePosition] = [ [row1,col1] ... [rown, coln] ] .. position into board where stone is placed if no stone can be placed: return [] """ return [ ] if __name__ == "__main__": #load stones from file stones = base.loadStones("stones.txt") print("stones are", stones) #prepare board and marks board, marks = base.makeBoard10(); #create both players p1 = Player("pepa", board, marks, stones, 1) p2 = Player("franta", board, marks, stones, -1) #not necessary, only if you want to draw board to png files d = Drawer() d.draw(p1.board, p1.marks, "init.png"); moveidx = 0 while True: p1play = True p2play = True m = p1.move() #first player, we assume that a corrent output is returned #the following if/else is simplified. On Brute, we will check if return value #from move() is valid ... if len(m) == 0: p1play = False else: stoneIdx, stone = m stoneColor = stones[stoneIdx][0] base.writeBoard(p1.board, stone, stoneColor) #write stone to player1's board base.writeBoard(p2.board, stone, stoneColor) #write stone to player2's board p1.freeStones[ stoneIdx ] = False #tell player1 which stone is used p2.freeStones[ stoneIdx ] = False #tell player2 which stone is used d.draw(p2.board, p2.marks, "move-{:02d}a.png".format(moveidx)) #draw to png #now we call player2 and update boards/freeStones of both players m = p2.move() if len(m) == 0: p2play = False else: stoneIdx, stone = m stoneColor = stones[stoneIdx][0] base.writeBoard(p1.board, stone, stoneColor) base.writeBoard(p2.board, stone, stoneColor) p1.freeStones[ stoneIdx ] = False p2.freeStones[ stoneIdx ] = False d.draw(p1.board, p1.marks, "move-{:02d}b.png".format(moveidx)) #if both players return [] from move, the game ends if p1play == False and p2play == False: print("end of game") break moveidx+=1 print(" -- end of move ", moveidx, " score is ", p1.score(p1.player), p1.score(-p1.player) )
init()
je konstruktor třídy Player, v něm si definujte svoje proměnné (referencujte je přes self
)
self.player
je buď 1 (v tom případě hraje hráč za kolečka), nebo -1 (hraje za křížky)
self.board
je hrací deska. Je to 2D pole, přistupujeme do něj self.board[row][col]
(tj. nejdřív řádek, pak sloupec).
self.board[row][col] == 0
, tak buňka row,col je prázdná
self.board[row][col]
označuje, která barva je na této pozici umístěna
self.marks
je 2D pole značek, má stejné rozměry jako self.board
. Slouží k výpočtu skóre.
self.marks[row][col] == 0
, tak na pozici row, col není žádná značka
self.marks[row][col] == self.player
, je na pozici row,col umístěna značka hráče
self.marks[row][col] == -self.player
, je na pozici row,col umístěna značka soupeře
self.stones
je pole kamenů, jeho formát je stejný jako v HW08:
self.stones[i]
je i-tý kamen
self.stones[i][0]
je barva i-tého kamene:
self.stones[i][1]
je pole souřadnic i-tého kamene [[row1,col1], ... [rown],[coln]]
self.freeStones
je 1D pole hodnot True/False.
self.freeStones[i] == True
, pak kamen s indexem i
je volný a lze jej (pokud je to možné) umístit na desku
self.stones
a self.freeStones
jsou úzce svázané:
self.stones[i]
self.freeStones[i]
self.board
a self.freeStones
bude Brute/Turnaj zapisovat aktuální stav hrací desky po každém provedeném tahu. Je tedy nutné:
self.freeStones
move()
. Ta vrací buď prázné pole (pokud nelze táhnout), nebo index kamene a jeho pozici na hrací desce
def move(self): return [ 2, [ [0,1],[0,2],[0,3] ] ]
def move(self): return [ 2, [ [0,9],[1,9],[2,9] ] ]
def move(self): if self.freeStones[3] == True: #kamen 3 je volny, muzeme ho zkusit dat na hraci desku
def move(self): for i in range(len(self.freeStones))): if self.freeStones[i] == True: #kamen i je volny else: #kamen i neni volny, nema smysl pokouset se umistit jej
self.inBoard(row,col)
vrací True, pokud je souřadnice row,col uvnitř hrací desky:
if self.inBoard(row, col) and self.board[row][col] == 0: #bunka row,col je prazda a uvnitr hraci desky
self.isEmpty()
vrací True, pokud je hrací deska prázdná
if self.isEmpty(): #deska je prazdna, tj. jedna se o prvni tah, lze umistit jakykoliv kamen na jakekoliv misto
self.score(player)
vypočítá skóre pro hráče player:
myScore = self.score(self.player) opponentScore = self.score(-self.player)
self.algorithm
zde si napište jméno algoritmu/programu/strategie, kterou testujete
self.tournament
je True, pokud je hráč puštěn v turnajovém módu. Lze využít např, tak, že na Brutovi se provede pouze základní (jednoduchý a rychlý) hráč, zatímco v turnaji se zapne např. lepší strategie apod..:
if self.tournament: #zapni chytrou herni strategie.. hraju proti ostatnim studentum else: #hraju proti Brutovi, pohoda .. neni treba vyhrat
base.loadStones(filename)
slouží k načtení kamenů
stones = base.loadStones("stones.txt")
base.makeBoard10()
vytvoří testovací hrací desku o velikosti 10×10 a také pole marks se značkami hráčů:
board, marks = base.makeBoard10()
self.board
) obou hráčů a aktualizuje jejich self.freeStones
move()
se hráč rozhoduje na základě aktuálního stavu hrací desky a vybírá z aktuálně dostupných kamenů
if name == “main”:
v souboru player.py
realizuje jednoduchou hru hráče sám proti sobě. Předpokládáme, že hráč hraje správně, tj. vrací validní pozici kamenu (uvnitř hrací desky, kameny se nepřekrývají atd..), jejich validní index.. nicméně tyto věci nejsou v souboru player.py kontrolovány a budou kontrolovány až na Brutovi.
python3 player.py