Table of Contents

Cvičení 9: Semestrální práce - LITS

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.

Ukázka hry

Tah 1, Hraje 1 Tah 2, Hraje 2 Tah 3, Hraje 1 Tah 4, Hraje 2
Tah 5, Hraje 1 Tah 6, Hraje 2 Tah 7, Hraje 1 Tah 8, Hraje 2
Tah 9, Hraje 1 Tah 10, Hraje 2 Tah 11, Hraje 1 Tah 12, Hraje 2
Tah 13, Hraje 1 Tah 14, Hraje 2 Tah 15, Hraje 1 Tah 16, Hraje 2

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”. }

Historie a balíček

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.

Pravidla

Pravidlo 2x2

Co je v balíčku

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) )

Význam proměnných ve třídě Player

metoda move()

    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

další pomocné metody a proměnné

 if self.inBoard(row, col) and self.board[row][col] == 0:
    #bunka row,col je prazda a uvnitr hraci desky

 if self.isEmpty():
    #deska je prazdna, tj. jedna se o prvni tah, lze umistit jakykoliv kamen na jakekoliv misto

    myScore = self.score(self.player)
    opponentScore = self.score(-self.player)

   if self.tournament: 
      #zapni chytrou herni strategie.. hraju proti ostatnim studentum
   else:
      #hraju proti Brutovi, pohoda .. neni treba vyhrat

  stones = base.loadStones("stones.txt")

   board, marks = base.makeBoard10()

Jak probíhá hra / jak hrát doma

  1. Brute vytvoří oba hráče, předá jim hrací desku a seznam kamenů (hráči sdíli stejnou skupinu kamenů)
  2. Pokud je hráč na tahu, volá se jeho metoda move()
  3. Následuje kontrola validnosti tahu (jestli je kamen volný, jestli je uvnitř desky, jestli se nepřekrývá atd.. dle pravidel)
  4. Pokud je kontrola v pořádku, Brute zapíše tah do hracích desek (self.board) obou hráčů a aktualizuje jejich self.freeStones
    • tj. při dalším volání move() se hráč rozhoduje na základě aktuálního stavu hrací desky a vybírá z aktuálně dostupných kamenů

python3 player.py

Jak odevzdat hráče

Turnaj