Table of Contents

Semestrální práce

Historie:

Pravidla hry:

Základní hrací ploha a její souřadnicový systém. Modrý hráč je na pozici (3,0), zelený na pozici ($n_x$-2, $n_y$-1).
Příklady validních překážek (černě) a nevalidních (červeně). Validní tahy.

Příklady umisťování překážek

Kdy nelze umístit překážku:

a b

Kdy lze překážku umístit:

Implementace:

Překážky

class Obstacle:
    """ Simple class to represent one part of each obstacle. The obstacle is defined by coordinates of cells
        between which the player cannot move
    """
 
    def __init__(self,fromx, fromy,  tox, toy):
        self.fromx = fromx
        self.fromy = fromy
        self.tox = tox
        self.toy = toy
 
    def __str__(self):
        return "(" + str(self.fromx) + "," + str(self.fromy) + ")->(" + str(self.tox) + "," + str(self.toy) + ")"
 
    def can_player_move(self, fromx, fromy, tox, toy):
        """
            return True, if a player can move from [fromx,fromy] to [tox,toy]. This only checks if THIS obstacle 
            prevents the move or not. 
        """
        if (self.fromx == fromx and self.fromy == fromy and self.tox == tox and self.toy == toy) or \
    (self.fromx == tox and self.fromy == toy and self.tox == fromx and self.toy == fromy):
               return False
        return True
 
    def is_valid_obstacle(self, sizex, sizey):
        """ return True, if the given obstacle is valid (is inside the board). Size of the board is sizex, sizey
        """
        return (self.fromx >= 0 and self.fromx < sizex and \
                self.fromy >= 0 and self.fromy < sizey and \
                self.tox >= 0 and self.tox < sizex and \
                self.toy >=0 and self.toy < sizey)
 
    def __eq__(self, other):
        return type(self) == type(other) and  self.fromx == other.fromx and self.fromy == other.fromy and self.tox == other.tox and self.toy == other.toy;

Příklad vytvoření validní překážky z obrázku:

#horizontalni
p1 = Obstacle(5,0, 5,1)
p2 = Obstacle(6,0, 6,1)
 
#vertikalni
p3 = Obstacle(3,5, 4,5)
p4 = Obstacle(3,6, 4,6)

Takové překážky bude vracet metoda Player.makeMove a Player.expandObstacles jako pole, tedy:

#.. somewhere in player.expandObstacles()
pa = Obstacle(3,5, 4,5)
pb = Obstacle(3,6, 4,6)
myObstacles = []
myObstacles.append(pa)
myObstacles.append(pb)
return myObstacles

Player

class Player:
    def __init__(self, name):
        self.name = name; #student's name, will be filled by BRUTE
        self.version = "version 3" #student' debug info, e.g. version, name of algorithm..
        self.myx = -1 #my position
        self.myy = -1
        self.opponentx = -1  #position of the oponent
        self.opponenty = -1
        self.sizex = -1  #size of the board. Will be filled using initialization
        self.sizey = -1
        self.obstacles = []  #I have no 
        self.max_obstacles = -1
        self.my_goal_row = -1  #index of row, where is my goal zone
        self.my_obstacles = 0 
 
    def initialization(self, sizex, sizey, myx, myy, opponentx, opponenty, max_obstacles, list_of_obstacles):
        """
            This method is called by the game Manager to tell the player where it is, where is the oponent, where are obstacles and how
            many obstacle the player can use.
 
            sizex, sizey - dimensions of the board
            startx, starty - my initial position at the board
            ostartx, ostarty - initial position of the oponent
            max_obstacles - how many obstacles I can use
            list_of_obstacles - array of initial obstacles (objects Obstacles).
        """
        self.sizex = sizex
        self.sizey = sizey
        self.myx = myx
        self.myy = myy
        self.opponentx = opponentx
        self.opponenty = opponenty
        self.max_obstacles = max_obstacles
        self.obstacles = list_of_obstacles
        self.my_obstacles = 0 #number of my obstacles
 
 
        if (self.myy == 0):
            self.my_goal_row = sizey -1
        else:
            self.my_goal_row = 0
 
    def is_in_board(self, x,y):
        """ return True if position (x,y) is in the board 
            TODO: implement in class
        """
        return True
 
    def can_player_move(self, x,y):
        """ return True, if this player can move from (self.myx, self.myx) to the cell (x, y)
            TODO: implement in class
        """        
        return True
 
 
 
    #this is called by the manager. this function should return either new position of this paper (0, (x,y)) or
    #position of new obstacles (1, x1,y1,x2,y2);
    def make_move(self):
        """ this function is called by the game Manager to get the move of this player. The move is
            either new position of the player or newly placed obstacle. 
            Return always TWO variables: the first is integer, the second is LIST
 
            if value is 1: the list is [x, y] - new position of the player
            if value is 2: the list is [o1, o2] - list of two Obstacles - this means that the player placed new obstacle
            if value is None: the list is ignored - this means that player cannot move
 
            TODO: implement by yourself
 
            #the following code is just example to show how to return new postion, new obstacle or None.
 
            #example of returning a position, try first go to down, then left, then right, then up
            #return 1, [self.myx, self.myy]; #move up toward the goal zone
 
            o1 = Obstacle(x1,y1, x2, y2);
            o2 = Obstacle(xx1,yy1, xx2, yy2);
            if (o1.is_valid_obstacle(self.sizex, self.sizey) and o2.is_valid_obstacle(self.sizex, self.sizey)):
               self.obstacles.append(o1)
               self.obstacles.append(o2)
               self.my_obstacles+=1
               return 2, [ o1, o2 ]
            """
        return None
 
 
 
 
    def opponent_move(self, moveType, result):
        """ this is called by the Manager to pass result of oponent's move. moveType and result has the same
            meaning as in the self.move method
        """
        if (moveType == 1):
            #the other player moved itself, let's update its position
            self.opponentx = result[0]
            self.opponenty = result[1]
        elif (moveType == 2):
            #the other player placed a new obstacle.
            if (len(result) == 2):
                self.obstacles.append(result[0])
                self.obstacles.append(result[1])
            else:
                #this shouldn't happen, it will be checked by the manager
                print("Error, oponent returned wrong move!!")
        else:
            print("Oponent return None")
 
 
    def expand_player(self):
        """ returns LIST of [x,y] positions where this player can move. It can be empty.
            TODO: implement by yourself
        """
        my_moves = []
        return my_moves
 
    def expand_obstacles(self):
       """ return LIST of [o1,o2] of all possible pairs of obstacles. can be empty if the player cannot
          place any obstacle anymore
            TODO: implement by yourself
       """
       my_obstacles = []
       return my_obstacles 

Příklad práce s hráčem (doporučujeme začínat takto):

p = Player("pepa")
p.initialization(10,10, 0,0 9,9, 5, []); #board 10x10, first player at (0,0), second at (9,9), max 5 obstacles, empty list of obstacles 
 
my_moves = p.expand_player()
 
#or 
my_obstacles = p.expand_obstacles()

Manager

from obstacle import *
 
class Manager:    
    """
        Example of game Manager. This class is responsible to call methods of both players. This is simple version
        of the manager (e.g., we do not control validiy of obstacles returned by players etc..).
    """
 
    def __init__(self, p1, p2, sizex, sizey):
        """ p1,p2 are objects of class Player
            sizex,sizey is dimension of the board
        """
        self.p1 = p1
        self.p2 = p2
        self.sizex = sizex
        self.sizey = sizey
 
 
    def init(self):
        """
            Example of game initialization. We create positions of both players (x1,y1) and (x2,y2) and 
            call initialization on each player. 
        """
        self.x1 = self.sizex//2; 
        self.y1 = 0;
 
        self.x2 = self.sizex//2;
        self.y2 = self.sizey -1;
 
        #create an initial obstacle. As each obstacle has to have length 2, we have to create TWO objects 
        obstacles = []
        obstacles.append( Obstacle(2,self.sizex//2,2,self.sizey//2 + 1) ) #horizontal obstacle at column 1
        obstacles.append( Obstacle(3,self.sizex//2,3,self.sizey//2 + 1) ) #horizontal obstacle at column 2
 
        self.p1.initialization(self.sizex, self.sizey, self.x1, self.y1, self.x2, self.y2, 4, obstacles)
        self.p2.initialization(self.sizex, self.sizey, self.x2, self.y2, self.x1, self.y1, 4, obstacles)
 
    def check_result(self, player, moveType, result):
        """ return True, of result of player.move is valid
        """
        if (moveType == 1 and len(result) == 2):
            if (player == 1):
                self.x1,self.y1 = result[0], result[1]
            else:
                self.x2,self.y2 = result[0], result[1]
            return True;
        if (moveType == 2 and len(result) == 2 and type(result[0]) == Obstacle and type(result[1]) == Obstacle):
            obstacles.append(result[0])
            obstacles.append(result[1])
            return True;
        if (moveType == None):
            return True;
 
        print("Upps, player1 returned invalid output from move()");
        quit()
 
    def is_winner(self):
        """ return true if one of player is at goal zone 
        """
        return self.y1 == self.sizey-1 or self.y2 == 0
 
 
    def game(self):
        """ Example how the game will be handled during the tournament. The player p1 will always start first.
            The game is organized this way:
            1. tell p1 where is p2 (p1.oppositeMove())
            2. ask p1 to move (i.e., to move itself or place new obstacles)
            3. tell p2 what move p1 did
            4. ask p2 to move
        """
 
        moveType2 = 1;
        result2 = [ self.x2, self.y2 ]
 
        cnt = 0;
 
        while(True):
            self.p1.opponent_move( moveType2, result2 )
            moveType1, result1 = self.p1.make_move()
            print("p1 returned: ", moveType1, result1[0], result1[1]);
 
            self.check_result(1, moveType1, result1)
 
            if (self.is_winner()):
                print("P1 wins");
                return
 
            self.p2.opponent_move(moveType1, result1)
 
            moveType2, result2 = self.p2.make_move()
            print("p2 returned: ", moveType2, result2[0], result2[1]);
            self.check_result(2, moveType2, result2)
            if (self.is_winner()):
                print("p2 wins!");
                return;
            print("p1=(",self.x1, self.y1,"), p2=(",self.x2,self.y2,")")
        print("end of the game");

Příklad hry

from manager import *
from player import *
p1 = Player("pepa")
p2 = Player("franta")
 
m = Manager(p1,p2, 15, 15);
m.init()
m.game()

Jak hrát

from manger import 
impor randomPlayer as RP
import player as P
 
p1 = P.Player("pepa")
p2 = RP.Player("franta")
#zbytek je stejný jako výše.

Jak bude hodnoceno a jak odevzávat

.

Příklad expanze překážek

Výchozí stav:

Vytvoření hry. Hráči v 0. sloupci. Jedna dvou-buňková překážka na začátku

p = Player("pepa")
o1 = Obstacle(0,1, 0,2) #horizontal obstacle (black in the following images)
o1 = Obstacle(1,1, 1,2)
p.initialization(4,4, 0,0 0,3, 5, [o1, o2]);
 
ob = p.expand_obstacles()
 
#in this case, the list 'ob' should have 11 items. The order of the returned obstacles does not matter

Validní tahy:

Situaci vlevo-nahoře odpovídá tento fragment kódu:

def expand_player(self):
   my_moves = []
   o1 = Obstacle(0,0,  0,1)
   o1 = Obstacle(1,0,  1,1)
   my_moves.append( [ o1, o2 ] );
   ... code for other obstacles ...
   return my_moves

Příklad inicializace hry s překážkami

Příklad předání 2 překážek.

#vertical obstacle
o1 = Obstacle(0,0, 1, 0;
o2 = Obstacle(0,1, 1, 1;
 
#horizontal one
o3 = Obstacle(1,1,1,2);
o4 = Obstacle(2,1,2,2);
 
player.initialization(5,5, 0,0, 4,4, [ o1, o2, o3, o4 ] );