Example #1
0
def test_data_repository():
    width = 10
    height = 10
    seed = random.randint(76, 76000)
    print("seed:", seed)
    a = SimPhysicalInterface(width, height, seed)
    d = DataRepository(width, height)

    print(a.env.text_map())

    visit(a, d)

    c = d.find_target(a.position, Coordinate(0, 0))
    while c != Coordinate(0, 0):
        print("target:", c)

        p = d.find_path(a.position, c)
        print("path:", p)
        if len(p) > 0:
            a.turn(p[0])
            a.forward()
            visit(a, d)

        print(d.text_map(a.position, a.facing))
        input()
        c = d.find_target(a.position, Coordinate(0, 0))
Example #2
0
    def get_lines(self,color,coord):
        pos_fin = Coordinate(coord.x,coord.y)
        pos_inicial = Coordinate(coord.x,coord.y)
        can_fichas_volteables = 0
        vec_lineas = []
        for inc_fila in xrange(-1,2):
            for inc_col in xrange(-1,2):
                pos_fin.x = pos_inicial.x + inc_fila
                pos_fin.y = pos_inicial.y + inc_col
                #Verifica que haya al menos una ficha del color opuesto para voltear
                if Referee.can_turn(color, pos_inicial, inc_fila, inc_col, self):
                    hash_linea = {}
                    vec_casillas = []
                    #Contar las fichas volteables en esa linea
                    while True:
                        can_fichas_volteables += 1
                        vec_casillas.append(Coordinate(pos_fin.x,pos_fin.y))
                        pos_fin.x += inc_fila
                        pos_fin.y += inc_col
                        if not self.__casilla[pos_fin.x][pos_fin.y] == -color:
                            break
                    hash_linea["casilla_inicial"] = pos_inicial
                    hash_linea["casilla_final"] =  Coordinate(pos_fin.x,pos_fin.y)
                    hash_linea["can_fichas_volteables"] = can_fichas_volteables
                    hash_linea["casillas_volteables"] = vec_casillas
                    vec_lineas.append(hash_linea)
                    can_fichas_volteables = 0

        return vec_lineas
Example #3
0
class Direction:
    LEFT = Coordinate(-1, 0)
    RIGHT = Coordinate(1, 0)
    DOWN = Coordinate(0, -1)
    UP = Coordinate(0, 1)
    STAY = Coordinate(0, 0)

    @staticmethod
    def all():
        return {
            Direction.LEFT, Direction.RIGHT, Direction.UP, Direction.DOWN,
            Direction.STAY
        }

    @staticmethod
    def as_movement_delta(direction):
        directions = {
            "DOWN": (0, 1),
            "UP": (0, -1),
            "RIGHT": (1, 0),
            "LEFT": (-1, 0),
            "STAY": (0, 0)
        }

        return directions[direction.upper()]
Example #4
0
    def is_at_least_one_move(color, tablero):
        dimension = tablero.get_dimension()
        pos = Coordinate()

        for i in range (0,dimension):
            for j in range (0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    return True

        return False
Example #5
0
    def is_at_least_one_move(color, tablero):
        dimension = tablero.get_dimension()
        pos = Coordinate()

        for i in range(0, dimension):
            for j in range(0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    return True

        return False
Example #6
0
    def number_of_successors(color, tablero):
        cant_sucesores = 0
        pos = Coordinate()
        dimension = tablero.get_dimension()

        for i in range (0,dimension):
            for j in range (0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    cant_sucesores += 1

        return cant_sucesores
Example #7
0
    def number_of_successors(color, tablero):
        cant_sucesores = 0
        pos = Coordinate()
        dimension = tablero.get_dimension()

        for i in range(0, dimension):
            for j in range(0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    cant_sucesores += 1

        return cant_sucesores
Example #8
0
    def possibles_moves(color, tablero):
        coordenadas = []
        pos = Coordinate()
        dimension = tablero.get_dimension()

        for i in range (0,dimension):
            for j in range (0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    nueva_pos = Coordinate(i, j)
                    coordenadas.append(nueva_pos)

        return coordenadas
Example #9
0
    def possibles_moves(color, tablero):
        coordenadas = []
        pos = Coordinate()
        dimension = tablero.get_dimension()

        for i in range(0, dimension):
            for j in range(0, dimension):
                pos.x = i
                pos.y = j
                if Referee.is_valid_move(color, pos, tablero):
                    nueva_pos = Coordinate(i, j)
                    coordenadas.append(nueva_pos)

        return coordenadas
Example #10
0
 def __init__(self,
              tablero,
              turno=NEGRO,
              etiqueta=MAX,
              profundidad=0,
              cantidad_hnos=0):
     self.tablero = tablero.copy()
     self.etiqueta = etiqueta
     self.profundidad = profundidad
     self.turno = turno
     self.cantidad_hnos = cantidad_hnos
     #Guardo la coordenada para llegar al mejor sucesor de este estado
     self.mejor_sucesor = Coordinate()
     #Guardo la accion que dio nacimiento al estado
     self.iniciador = Coordinate()
Example #11
0
    def extract_coordinates(self) -> Coordinate:
        """ inverse of coord_str starting from index cursor
            :returns Coordinate """
        x = self.extract_number()
        y = self.extract_number()

        return Coordinate(x, y)
Example #12
0
    def get_lines(self, color, coord):
        pos_fin = Coordinate(coord.x, coord.y)
        pos_inicial = Coordinate(coord.x, coord.y)
        can_fichas_volteables = 0
        vec_lineas = []
        for inc_fila in xrange(-1, 2):
            for inc_col in xrange(-1, 2):
                pos_fin.x = pos_inicial.x + inc_fila
                pos_fin.y = pos_inicial.y + inc_col
                #Verifica que haya al menos una ficha del color opuesto para voltear
                if Referee.can_turn(color, pos_inicial, inc_fila, inc_col,
                                    self):
                    hash_linea = {}
                    vec_casillas = []
                    #Contar las fichas volteables en esa linea
                    while True:
                        can_fichas_volteables += 1
                        vec_casillas.append(Coordinate(pos_fin.x, pos_fin.y))
                        pos_fin.x += inc_fila
                        pos_fin.y += inc_col
                        if not self.__casilla[pos_fin.x][pos_fin.y] == -color:
                            break
                    hash_linea["casilla_inicial"] = pos_inicial
                    hash_linea["casilla_final"] = Coordinate(
                        pos_fin.x, pos_fin.y)
                    hash_linea["can_fichas_volteables"] = can_fichas_volteables
                    hash_linea["casillas_volteables"] = vec_casillas
                    vec_lineas.append(hash_linea)
                    can_fichas_volteables = 0

        return vec_lineas
Example #13
0
    def turn_pieces(self, color, pos_ini):
        pos_fin = Coordinate(pos_ini.x, pos_ini.y)

        for inc_fila in xrange(-1, 2):
            for inc_col in xrange(-1, 2):
                pos_fin.x = pos_ini.x + inc_fila
                pos_fin.y = pos_ini.y + inc_col
                #Verifica que haya al menos una ficha del color opuesto para voltear
                if Referee.can_turn(color, pos_ini, inc_fila, inc_col, self):
                    #Voltear las fichas
                    while True:
                        self.__casilla[pos_fin.x][pos_fin.y] = color
                        pos_fin.x += inc_fila
                        pos_fin.y += inc_col
                        if not self.__casilla[pos_fin.x][pos_fin.y] == -color:
                            break
        #Actualizo los contadores de las fichas blancas o negras dependiendo del color
        self.update_pieces_counters()
Example #14
0
    def turn_pieces(self, color, pos_ini):
        pos_fin = Coordinate(pos_ini.x, pos_ini.y)

        for inc_fila in xrange(-1,2):
            for inc_col in xrange(-1,2):
                pos_fin.x = pos_ini.x + inc_fila
                pos_fin.y = pos_ini.y + inc_col
                #Verifica que haya al menos una ficha del color opuesto para voltear
                if Referee.can_turn(color, pos_ini, inc_fila, inc_col, self):
                    #Voltear las fichas
                    while True:
                        self.__casilla[pos_fin.x][pos_fin.y] = color
                        pos_fin.x += inc_fila
                        pos_fin.y += inc_col
                        if not self.__casilla[pos_fin.x][pos_fin.y] == -color:
                            break
        #Actualizo los contadores de las fichas blancas o negras dependiendo del color
        self.update_pieces_counters()
Example #15
0
    def __number_stable_boxes(self,tablero):
        pos = Coordinate()
        estables = []
        dim = tablero.get_dimension()
        for _ in xrange(dim):
            estables.append([False]*dim)

        cambio_estado = True
        while (cambio_estado):
            cambio_estado = False
            for i in xrange(0,dim):
                for j in xrange(0,dim):
                    pos.x = i
                    pos.y = j
                    if tablero.get_valor_casilla(i,j) != VACIO and not estables[i][j] and not self.__can_turn(pos, tablero, estables):
                        estables[i][j] = True
                        cambio_estado = True

        return estables
Example #16
0
    def __border_pieces(self,tablero, color):
        can_fichas_frontera = 0
        dim = tablero.get_dimension()

        for i in xrange(0,dim):
            for j in xrange(0,dim):
                es_frontera = False
                if tablero.get_valor_casilla(i,j) == color:
                    aux_coord = Coordinate()
                    for inc_fila in xrange(-1,2):
                        for inc_col in xrange(-1,2):
                            aux_coord.x = i + inc_fila
                            aux_coord.y = j + inc_col
                            if not (inc_fila == 0 and inc_col == 0 and tablero.valid_pos(aux_coord) and tablero.get_valor_casilla(aux_coord.x,aux_coord.y) == VACIO):
                                es_frontera = True
                                inc_fila = 2
                                break
                if es_frontera:
                    can_fichas_frontera += 1

        return can_fichas_frontera
Example #17
0
    def __number_stable_boxes(self, tablero):
        pos = Coordinate()
        estables = []
        dim = tablero.get_dimension()
        for _ in xrange(dim):
            estables.append([False] * dim)

        cambio_estado = True
        while (cambio_estado):
            cambio_estado = False
            for i in xrange(0, dim):
                for j in xrange(0, dim):
                    pos.x = i
                    pos.y = j
                    if tablero.get_valor_casilla(
                            i, j
                    ) != VACIO and not estables[i][j] and not self.__can_turn(
                            pos, tablero, estables):
                        estables[i][j] = True
                        cambio_estado = True

        return estables
Example #18
0
    def parse_telemetry(self):
        """
        Parse a command received and turn it into a coordinate if possible

        :return: The coordinate parsed from the command stream
        """
        telemetry = self.buffer
        self.buffer = ""
        if telemetry[0] == '<':
            if telemetry[len(telemetry) - 1] == '>':
                values = telemetry[1:len(telemetry)-1].split(',')
                coord = Coordinate(int(values[0]), int(values[1]))
                return coord
        return None
Example #19
0
 def __init__(self, nivel=1):
     if nivel == Ai.FACIL:
         self.__profundidad_maxima = 1
         self.__frontera_peso = 1  #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 0  #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 0  #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 8
     elif nivel == Ai.MEDIO:
         self.__profundidad_maxima = 2
         self.__frontera_peso = 1  #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 0  #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 3  #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 1
     elif nivel == Ai.DIFICIL:
         self.__profundidad_maxima = 3
         self.__frontera_peso = 2  #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 1  #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 5  #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 4
     else:
         raise Exception("Nivel desconocido (Ai Class)")
     #Guardo la ultima jugada de la PC
     self.__ultima_jugada = Coordinate(0, 0)
Example #20
0
    def __border_pieces(self, tablero, color):
        can_fichas_frontera = 0
        dim = tablero.get_dimension()

        for i in xrange(0, dim):
            for j in xrange(0, dim):
                es_frontera = False
                if tablero.get_valor_casilla(i, j) == color:
                    aux_coord = Coordinate()
                    for inc_fila in xrange(-1, 2):
                        for inc_col in xrange(-1, 2):
                            aux_coord.x = i + inc_fila
                            aux_coord.y = j + inc_col
                            if not (inc_fila == 0 and inc_col == 0
                                    and tablero.valid_pos(aux_coord)
                                    and tablero.get_valor_casilla(
                                        aux_coord.x, aux_coord.y) == VACIO):
                                es_frontera = True
                                inc_fila = 2
                                break
                if es_frontera:
                    can_fichas_frontera += 1

        return can_fichas_frontera
Example #21
0
def test_message():
    print(Message.coord_str(Coordinate(536, 0)))
    assert Message.coord_str(Coordinate(536, 0)) == "536 0 "
    print("passed Message.coord_str")

    Message.set_my_robot_id(1)

    m = Message()
    m.add_objective(Coordinate(3, 5), 2.0)
    print(m.get_data())
    assert m.get_data() == Message.BEGIN + "1 1 j3 5 2.0k" + Message.END
    print("passed add_objective")

    m._cursor = 10
    ov = m.extract_objective_value()
    print(ov)
    assert ov == 2.0
    print("passed extract_objective_value")

    m = Message()
    m.add_obstacle(Coordinate(0, 6), Knowledge.YES)
    print(m.get_data())
    assert m.get_data() == Message.BEGIN + "1 2 s0 6 yt" + Message.END
    print("passed add_obstacle")

    m._cursor = 6
    co = m.extract_coordinates()
    print(co)
    assert co == Coordinate(0, 6)
    print("passed extract coordinate")

    d = DataRepository(10, 10)
    m.add_objective(Coordinate(6, 0), 7.0)
    m.handle(d)
    obs = d.get_obstacle(Coordinate(0, 6))
    obj = d.get_objective(Coordinate(6, 0))
    print(obs, obj)
    assert obs == Knowledge.YES
    assert obj == 7.0
    print("passed handle")
Example #22
0
    def can_turn(color, pos_ini, dir_horizontal, dir_vertical, tablero):
        pos_fin = Coordinate(pos_ini.x + dir_horizontal,
                             pos_ini.y + dir_vertical)
        if not tablero.valid_coord(pos_fin):
            return False

        # Verifica que haya al menos una ficha del color opuesto en esa direccion
        if tablero.get_casillas()[pos_fin.x][pos_fin.y] != -1 * color:
            return False

        # Ejecuto el while mientras la casilla del tablero contenga piezas del color opuesto,
        # es decir no sea VACIO, ni de mi color, ni este fuera del tablero
        while True:
            pos_fin.x += dir_horizontal
            pos_fin.y += dir_vertical
            if not tablero.valid_coord(pos_fin):
                return False
            if tablero.get_casillas()[pos_fin.x][pos_fin.y] == board.VACIO:
                return False
            elif tablero.get_casillas()[pos_fin.x][pos_fin.y] == color:
                return True
Example #23
0
 def __init__(self, nivel=1):
     if nivel == Ai.FACIL:
         self.__profundidad_maxima = 1
         self.__frontera_peso = 1      #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 0     #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 0   #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 8
     elif nivel == Ai.MEDIO:
         self.__profundidad_maxima = 2
         self.__frontera_peso = 1      #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 0     #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 3   #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 1
     elif nivel == Ai.DIFICIL:
         self.__profundidad_maxima = 3
         self.__frontera_peso = 2      #Cuanto mas fichas tengas en la frontera es peor
         self.__movilidad_peso = 1     #Cuantas jugadas posible se tiene
         self.__estabilidad_peso = 5  #Cuantas mas fichas logres estabilizar en la jugada mejor
         self.__diferencia_cantidad_fichas_peso = 4
     else:
         raise Exception("Nivel desconocido (Ai Class)")
     #Guardo la ultima jugada de la PC
     self.__ultima_jugada = Coordinate(0,0)
 def __init__(self):
     self.position = Coordinate()
     self.facing = Direction.EAST
Example #25
0
def create_robot_with_options(options: dict) -> Robot:
    return Robot(options["width"], options["height"],
                 Coordinate(options["home_x"], options["home_y"]),
                 options["seed"], options["robot_id"], options["robot_count"])
Example #26
0
class Ai:
    #NIVELES
    FACIL = 1
    MEDIO = 2
    DIFICIL = 3

    def __init__(self, nivel=1):
        if nivel == Ai.FACIL:
            self.__profundidad_maxima = 1
            self.__frontera_peso = 1      #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 0     #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 0   #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 8
        elif nivel == Ai.MEDIO:
            self.__profundidad_maxima = 2
            self.__frontera_peso = 1      #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 0     #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 3   #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 1
        elif nivel == Ai.DIFICIL:
            self.__profundidad_maxima = 3
            self.__frontera_peso = 2      #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 1     #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 5  #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 4
        else:
            raise Exception("Nivel desconocido (Ai Class)")
        #Guardo la ultima jugada de la PC
        self.__ultima_jugada = Coordinate(0,0)

    def get_last_move(self):
        return self.__ultima_jugada

    def play(self, tablero, turno):
        profundidad_raiz = 0
        cantidad_hnos_raiz = 0
        if Referee.is_at_least_one_move(turno, tablero):
            estado_raiz = State(tablero,turno,MAX,profundidad_raiz,cantidad_hnos_raiz)
            self.__negamax(estado_raiz, MEN_INFI, MAS_INFI)
            self.__ultima_jugada.set(estado_raiz.mejor_sucesor)
            return True
        else:
            return False

    def __negamax(self, estado, alpha, beta):
        if self.__is_goal_state(estado):
            return self.__goal_state_value(estado)
        elif self.__is_leaf(estado):
            l = self.__value(estado)
            return l
        else:
            e = MEN_INFI
            n_estados = self.__childrens(estado)
            for nuevo_estado in n_estados:
                e = -1 * self.__negamax(nuevo_estado, -1*beta, -1*alpha)
                if beta <= e:
                    return e
                if alpha < e:
                    alpha = e
                    estado.mejor_sucesor = nuevo_estado.iniciador
            return e

    def __is_goal_state(self,estado):
        #Si no existen mas jugadas para ninguno de los colores con el tablero actual entonces el juego termino y estamos en una hoja
        if not Referee.is_at_least_one_move(estado.turno, estado.tablero):
            if not Referee.is_at_least_one_move(-1*estado.turno, estado.tablero):
                return True
            else:
                return False
        else:
            return False

    def __goal_state_value(self,estado):
        diferencia_fichas = estado.tablero.get_can_fichas_blancas() - estado.tablero.get_can_fichas_negras()
        #Ganaron las blancas
        if diferencia_fichas > 0:
            if estado.turno == BLANCO:
                return ESTADO_GANADOR + diferencia_fichas
            else:
                return ESTADO_PERDEDOR + diferencia_fichas
        #Ganaron las negras
        elif diferencia_fichas < 0:
            if estado.turno == NEGRO:
                return ESTADO_GANADOR + diferencia_fichas
            else:
                return ESTADO_PERDEDOR + diferencia_fichas
        #Empate
        else:
            return ESTADO_EMPATE

    def __is_leaf(self,estado):
        #Si la profundidad del nodo actual es mayor (nunca deberia llegar) o igual ya estamos en la hoja del recorrido actual
        if estado.profundidad >= self.__profundidad_maxima:
            return True
        else:
            if len(Referee.possibles_moves(estado.turno,estado.tablero)) == 0:
                return True
            else:
                return False

    def __childrens(self,estado):
        n_etiqueta = estado.etiqueta * -1
        n_profundidad = estado.profundidad + 1
        n_turno = estado.turno * -1
        aux_tablero = Board(estado.tablero.get_dimension())
        aux_tablero.set_casillas(estado.tablero.get_casillas())
        nuevos_estados = []

        lista_jugadas = Referee.possibles_moves(estado.turno,estado.tablero)
        can_hijos = len(lista_jugadas)
        for jugada in lista_jugadas:
            aux_tablero.set_piece_and_turn_oponent_pieces(jugada,estado.turno)
            #Creo el nuevo estado
            n_estado = State(aux_tablero,n_turno,n_etiqueta,n_profundidad,can_hijos)
            n_estado.iniciador = jugada
            nuevos_estados.append(n_estado)
            aux_tablero.set_casillas(estado.tablero.get_casillas())

        return nuevos_estados

    def __value(self,estado):
        tablero = estado.tablero
        if estado.turno == BLANCO:
            fichas_jugador = tablero.get_can_fichas_blancas()
            fichas_oponente = tablero.get_can_fichas_negras()
        else:
            fichas_jugador = tablero.get_can_fichas_negras()
            fichas_oponente = tablero.get_can_fichas_blancas()
        movimientos_validos_oponente = estado.cantidad_hnos
        jugador_frontera = self.__border_pieces(tablero, estado.turno)
        oponente_frontera = self.__border_pieces(tablero, -1*estado.turno)
        movimientos_validos = Referee.number_of_successors(estado.turno, tablero)
        fichas_estables_jugador = self.__stable_pieces(tablero, estado.turno)
        fichas_estables_oponente = self.__stable_pieces(tablero, -1*estado.turno)
        dif_can_fichas = fichas_jugador - fichas_oponente

        v = self.__frontera_peso * (oponente_frontera - jugador_frontera) + self.__movilidad_peso * estado.turno * (movimientos_validos - movimientos_validos_oponente) + self.__estabilidad_peso * (fichas_estables_jugador - fichas_estables_oponente) + self.__diferencia_cantidad_fichas_peso * dif_can_fichas
        return v

    def __border_pieces(self,tablero, color):
        can_fichas_frontera = 0
        dim = tablero.get_dimension()

        for i in xrange(0,dim):
            for j in xrange(0,dim):
                es_frontera = False
                if tablero.get_valor_casilla(i,j) == color:
                    aux_coord = Coordinate()
                    for inc_fila in xrange(-1,2):
                        for inc_col in xrange(-1,2):
                            aux_coord.x = i + inc_fila
                            aux_coord.y = j + inc_col
                            if not (inc_fila == 0 and inc_col == 0 and tablero.valid_pos(aux_coord) and tablero.get_valor_casilla(aux_coord.x,aux_coord.y) == VACIO):
                                es_frontera = True
                                inc_fila = 2
                                break
                if es_frontera:
                    can_fichas_frontera += 1

        return can_fichas_frontera

    #Retorna el numero de fichas estables del color dado.
    def __stable_pieces(self,tablero, color):
        can_fichas_estables = 0
        dim = tablero.get_dimension()

        estables = self.__number_stable_boxes(tablero)

        for i in xrange(0,dim):
            for j in xrange(0,dim):
                if tablero.get_valor_casilla(i,j) == color and estables[i][j]:
                    can_fichas_estables += 1

        return can_fichas_estables

    #Retorna una matriz que indica cuales casillas son estables, es decir,
    #cuales casillas ya no pueden ser volteadas en lo que resta del juego.
    def __number_stable_boxes(self,tablero):
        pos = Coordinate()
        estables = []
        dim = tablero.get_dimension()
        for _ in xrange(dim):
            estables.append([False]*dim)

        cambio_estado = True
        while (cambio_estado):
            cambio_estado = False
            for i in xrange(0,dim):
                for j in xrange(0,dim):
                    pos.x = i
                    pos.y = j
                    if tablero.get_valor_casilla(i,j) != VACIO and not estables[i][j] and not self.__can_turn(pos, tablero, estables):
                        estables[i][j] = True
                        cambio_estado = True

        return estables

    #Retorna false si la ficha en dicha casilla ya no puede ser volteada en lo que resta del juego.
    #Una ficha puede ser volteada si hay una casilla vacia a ambos lados o
    #si hay una casilla vacia a un lado y una ficha inestable o una del contrario al otro lado.
    def __can_turn(self,casilla,tablero,estables):
        dim = tablero.get_dimension()
        #Obtiene el color de la ficha.
        color_ficha = tablero.get_valor_casilla(casilla.x,casilla.y)

        #Verifica cada eje posible (horizontal, vertical y diagonales)
        #Se verifica horizontalmente
        lado_uno_vacio = False
        lado_uno_inseguro = False
        lado_dos_vacio = False
        lado_dos_inseguro = False
        #Lado izquierdo.
        j = 0
        while j < casilla.y and not lado_uno_vacio:
            if tablero.get_valor_casilla(casilla.x,j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(casilla.x,j) != color_ficha or not estables[casilla.x][j]:
                lado_uno_inseguro = True
            j += 1
        #Lado derecho.
        j = casilla.y + 1
        while j < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(casilla.x,j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(casilla.x,j) != color_ficha or not estables[casilla.x][j]:
                lado_dos_inseguro = True
            j += 1
        if (lado_uno_vacio and lado_dos_vacio) or (lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro and lado_dos_vacio):
            return True

        #Se verifica verticalmente.
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Hacia arriba.
        i = 0
        while i < casilla.x and not lado_uno_vacio:
            if tablero.get_valor_casilla(i,casilla.y) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(i,casilla.y) != color_ficha or not estables[i][casilla.y]:
                lado_uno_inseguro = True
            i += 1
        #Hacia abajo.
        i = casilla.x + 1
        while i < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(i,casilla.y) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(i,casilla.y) != color_ficha or not estables[i][casilla.y]:
                lado_dos_inseguro = True
            i += 1
        if (lado_uno_vacio and lado_dos_vacio) or (lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro and lado_dos_vacio):
            return True

        #Se verifica la diagonal \
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Arriba izquierda.
        i = casilla.x - 1
        j = casilla.y - 1
        while i >= 0 and j >= 0 and not lado_uno_vacio:
            if tablero.get_valor_casilla(i,j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(i,j) != color_ficha or not estables[i][j]:
                lado_uno_inseguro = True
            i = i - 1
            j = j - 1
        #Abajo derecha.
        i = casilla.x + 1
        j = casilla.y + 1
        while i < dim and j < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(i,j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(i,j) != color_ficha or not estables[i][j]:
                lado_dos_inseguro = True
            i += 1
            j += 1
        if (lado_uno_vacio and lado_dos_vacio) or (lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro and lado_dos_vacio):
            return True

        #Se verifica la diagonal /
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Arriba derecha.
        i = casilla.x - 1
        j = casilla.y + 1
        while i >= 0 and j < dim and not lado_uno_vacio:
            if tablero.get_valor_casilla(i,j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(i,j) != color_ficha or not estables[i][j]:
                lado_uno_inseguro = True
            i = i - 1
            j += 1
        #Abajo izquierda.
        i = casilla.x + 1
        j = casilla.y - 1
        while i < dim and j >= 0 and not lado_dos_vacio:
            if tablero.get_valor_casilla(i,j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(i,j) != color_ficha or not estables[i][j]:
                lado_dos_inseguro = True
            i += 1
            j = j - 1
        if (lado_uno_vacio and lado_dos_vacio) or (lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro and lado_dos_vacio):
            return True

        #Todas las direcciones son estables, la casilla es estable.
        return False
Example #27
0
 def __init__(self, width: int, height: int, seed: int):
     super().__init__()
     self.env = EnvironmentSimulator()
     self.env.generate(width, height, seed)
     self.position = Coordinate(0, 0)
     self.facing = Direction.EAST
 def get(self, x_or_coordinate, y=None):
     i0, i1 = Coordinate.to_indexes(len(self._grid), x_or_coordinate, y)
     return self._grid[i0][i1]
Example #29
0
class Ai:
    #NIVELES
    FACIL = 1
    MEDIO = 2
    DIFICIL = 3

    def __init__(self, nivel=1):
        if nivel == Ai.FACIL:
            self.__profundidad_maxima = 1
            self.__frontera_peso = 1  #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 0  #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 0  #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 8
        elif nivel == Ai.MEDIO:
            self.__profundidad_maxima = 2
            self.__frontera_peso = 1  #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 0  #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 3  #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 1
        elif nivel == Ai.DIFICIL:
            self.__profundidad_maxima = 3
            self.__frontera_peso = 2  #Cuanto mas fichas tengas en la frontera es peor
            self.__movilidad_peso = 1  #Cuantas jugadas posible se tiene
            self.__estabilidad_peso = 5  #Cuantas mas fichas logres estabilizar en la jugada mejor
            self.__diferencia_cantidad_fichas_peso = 4
        else:
            raise Exception("Nivel desconocido (Ai Class)")
        #Guardo la ultima jugada de la PC
        self.__ultima_jugada = Coordinate(0, 0)

    def get_last_move(self):
        return self.__ultima_jugada

    def play(self, tablero, turno):
        profundidad_raiz = 0
        cantidad_hnos_raiz = 0
        if Referee.is_at_least_one_move(turno, tablero):
            estado_raiz = State(tablero, turno, MAX, profundidad_raiz,
                                cantidad_hnos_raiz)
            self.__negamax(estado_raiz, MEN_INFI, MAS_INFI)
            self.__ultima_jugada.set(estado_raiz.mejor_sucesor)
            return True
        else:
            return False

    def __negamax(self, estado, alpha, beta):
        if self.__is_goal_state(estado):
            return self.__goal_state_value(estado)
        elif self.__is_leaf(estado):
            l = self.__value(estado)
            return l
        else:
            e = MEN_INFI
            n_estados = self.__childrens(estado)
            for nuevo_estado in n_estados:
                e = -1 * self.__negamax(nuevo_estado, -1 * beta, -1 * alpha)
                if beta <= e:
                    return e
                if alpha < e:
                    alpha = e
                    estado.mejor_sucesor = nuevo_estado.iniciador
            return e

    def __is_goal_state(self, estado):
        #Si no existen mas jugadas para ninguno de los colores con el tablero actual entonces el juego termino y estamos en una hoja
        if not Referee.is_at_least_one_move(estado.turno, estado.tablero):
            if not Referee.is_at_least_one_move(-1 * estado.turno,
                                                estado.tablero):
                return True
            else:
                return False
        else:
            return False

    def __goal_state_value(self, estado):
        diferencia_fichas = estado.tablero.get_can_fichas_blancas(
        ) - estado.tablero.get_can_fichas_negras()
        #Ganaron las blancas
        if diferencia_fichas > 0:
            if estado.turno == BLANCO:
                return ESTADO_GANADOR + diferencia_fichas
            else:
                return ESTADO_PERDEDOR + diferencia_fichas
        #Ganaron las negras
        elif diferencia_fichas < 0:
            if estado.turno == NEGRO:
                return ESTADO_GANADOR + diferencia_fichas
            else:
                return ESTADO_PERDEDOR + diferencia_fichas
        #Empate
        else:
            return ESTADO_EMPATE

    def __is_leaf(self, estado):
        #Si la profundidad del nodo actual es mayor (nunca deberia llegar) o igual ya estamos en la hoja del recorrido actual
        if estado.profundidad >= self.__profundidad_maxima:
            return True
        else:
            if len(Referee.possibles_moves(estado.turno, estado.tablero)) == 0:
                return True
            else:
                return False

    def __childrens(self, estado):
        n_etiqueta = estado.etiqueta * -1
        n_profundidad = estado.profundidad + 1
        n_turno = estado.turno * -1
        aux_tablero = Board(estado.tablero.get_dimension())
        aux_tablero.set_casillas(estado.tablero.get_casillas())
        nuevos_estados = []

        lista_jugadas = Referee.possibles_moves(estado.turno, estado.tablero)
        can_hijos = len(lista_jugadas)
        for jugada in lista_jugadas:
            aux_tablero.set_piece_and_turn_oponent_pieces(jugada, estado.turno)
            #Creo el nuevo estado
            n_estado = State(aux_tablero, n_turno, n_etiqueta, n_profundidad,
                             can_hijos)
            n_estado.iniciador = jugada
            nuevos_estados.append(n_estado)
            aux_tablero.set_casillas(estado.tablero.get_casillas())

        return nuevos_estados

    def __value(self, estado):
        tablero = estado.tablero
        if estado.turno == BLANCO:
            fichas_jugador = tablero.get_can_fichas_blancas()
            fichas_oponente = tablero.get_can_fichas_negras()
        else:
            fichas_jugador = tablero.get_can_fichas_negras()
            fichas_oponente = tablero.get_can_fichas_blancas()
        movimientos_validos_oponente = estado.cantidad_hnos
        jugador_frontera = self.__border_pieces(tablero, estado.turno)
        oponente_frontera = self.__border_pieces(tablero, -1 * estado.turno)
        movimientos_validos = Referee.number_of_successors(
            estado.turno, tablero)
        fichas_estables_jugador = self.__stable_pieces(tablero, estado.turno)
        fichas_estables_oponente = self.__stable_pieces(
            tablero, -1 * estado.turno)
        dif_can_fichas = fichas_jugador - fichas_oponente

        v = self.__frontera_peso * (
            oponente_frontera -
            jugador_frontera) + self.__movilidad_peso * estado.turno * (
                movimientos_validos -
                movimientos_validos_oponente) + self.__estabilidad_peso * (
                    fichas_estables_jugador - fichas_estables_oponente
                ) + self.__diferencia_cantidad_fichas_peso * dif_can_fichas
        return v

    def __border_pieces(self, tablero, color):
        can_fichas_frontera = 0
        dim = tablero.get_dimension()

        for i in xrange(0, dim):
            for j in xrange(0, dim):
                es_frontera = False
                if tablero.get_valor_casilla(i, j) == color:
                    aux_coord = Coordinate()
                    for inc_fila in xrange(-1, 2):
                        for inc_col in xrange(-1, 2):
                            aux_coord.x = i + inc_fila
                            aux_coord.y = j + inc_col
                            if not (inc_fila == 0 and inc_col == 0
                                    and tablero.valid_pos(aux_coord)
                                    and tablero.get_valor_casilla(
                                        aux_coord.x, aux_coord.y) == VACIO):
                                es_frontera = True
                                inc_fila = 2
                                break
                if es_frontera:
                    can_fichas_frontera += 1

        return can_fichas_frontera

    #Retorna el numero de fichas estables del color dado.
    def __stable_pieces(self, tablero, color):
        can_fichas_estables = 0
        dim = tablero.get_dimension()

        estables = self.__number_stable_boxes(tablero)

        for i in xrange(0, dim):
            for j in xrange(0, dim):
                if tablero.get_valor_casilla(i, j) == color and estables[i][j]:
                    can_fichas_estables += 1

        return can_fichas_estables

    #Retorna una matriz que indica cuales casillas son estables, es decir,
    #cuales casillas ya no pueden ser volteadas en lo que resta del juego.
    def __number_stable_boxes(self, tablero):
        pos = Coordinate()
        estables = []
        dim = tablero.get_dimension()
        for _ in xrange(dim):
            estables.append([False] * dim)

        cambio_estado = True
        while (cambio_estado):
            cambio_estado = False
            for i in xrange(0, dim):
                for j in xrange(0, dim):
                    pos.x = i
                    pos.y = j
                    if tablero.get_valor_casilla(
                            i, j
                    ) != VACIO and not estables[i][j] and not self.__can_turn(
                            pos, tablero, estables):
                        estables[i][j] = True
                        cambio_estado = True

        return estables

    #Retorna false si la ficha en dicha casilla ya no puede ser volteada en lo que resta del juego.
    #Una ficha puede ser volteada si hay una casilla vacia a ambos lados o
    #si hay una casilla vacia a un lado y una ficha inestable o una del contrario al otro lado.
    def __can_turn(self, casilla, tablero, estables):
        dim = tablero.get_dimension()
        #Obtiene el color de la ficha.
        color_ficha = tablero.get_valor_casilla(casilla.x, casilla.y)

        #Verifica cada eje posible (horizontal, vertical y diagonales)
        #Se verifica horizontalmente
        lado_uno_vacio = False
        lado_uno_inseguro = False
        lado_dos_vacio = False
        lado_dos_inseguro = False
        #Lado izquierdo.
        j = 0
        while j < casilla.y and not lado_uno_vacio:
            if tablero.get_valor_casilla(casilla.x, j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(
                    casilla.x, j) != color_ficha or not estables[casilla.x][j]:
                lado_uno_inseguro = True
            j += 1
        #Lado derecho.
        j = casilla.y + 1
        while j < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(casilla.x, j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(
                    casilla.x, j) != color_ficha or not estables[casilla.x][j]:
                lado_dos_inseguro = True
            j += 1
        if (lado_uno_vacio and lado_dos_vacio) or (
                lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro
                                                          and lado_dos_vacio):
            return True

        #Se verifica verticalmente.
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Hacia arriba.
        i = 0
        while i < casilla.x and not lado_uno_vacio:
            if tablero.get_valor_casilla(i, casilla.y) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(
                    i, casilla.y) != color_ficha or not estables[i][casilla.y]:
                lado_uno_inseguro = True
            i += 1
        #Hacia abajo.
        i = casilla.x + 1
        while i < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(i, casilla.y) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(
                    i, casilla.y) != color_ficha or not estables[i][casilla.y]:
                lado_dos_inseguro = True
            i += 1
        if (lado_uno_vacio and lado_dos_vacio) or (
                lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro
                                                          and lado_dos_vacio):
            return True

        #Se verifica la diagonal \
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Arriba izquierda.
        i = casilla.x - 1
        j = casilla.y - 1
        while i >= 0 and j >= 0 and not lado_uno_vacio:
            if tablero.get_valor_casilla(i, j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(
                    i, j) != color_ficha or not estables[i][j]:
                lado_uno_inseguro = True
            i = i - 1
            j = j - 1
        #Abajo derecha.
        i = casilla.x + 1
        j = casilla.y + 1
        while i < dim and j < dim and not lado_dos_vacio:
            if tablero.get_valor_casilla(i, j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(
                    i, j) != color_ficha or not estables[i][j]:
                lado_dos_inseguro = True
            i += 1
            j += 1
        if (lado_uno_vacio and lado_dos_vacio) or (
                lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro
                                                          and lado_dos_vacio):
            return True

        #Se verifica la diagonal /
        lado_uno_vacio = False
        lado_dos_vacio = False
        lado_uno_inseguro = False
        lado_dos_inseguro = False
        #Arriba derecha.
        i = casilla.x - 1
        j = casilla.y + 1
        while i >= 0 and j < dim and not lado_uno_vacio:
            if tablero.get_valor_casilla(i, j) == VACIO:
                lado_uno_vacio = True
            elif tablero.get_valor_casilla(
                    i, j) != color_ficha or not estables[i][j]:
                lado_uno_inseguro = True
            i = i - 1
            j += 1
        #Abajo izquierda.
        i = casilla.x + 1
        j = casilla.y - 1
        while i < dim and j >= 0 and not lado_dos_vacio:
            if tablero.get_valor_casilla(i, j) == VACIO:
                lado_dos_vacio = True
            elif tablero.get_valor_casilla(
                    i, j) != color_ficha or not estables[i][j]:
                lado_dos_inseguro = True
            i += 1
            j = j - 1
        if (lado_uno_vacio and lado_dos_vacio) or (
                lado_uno_vacio and lado_dos_inseguro) or (lado_uno_inseguro
                                                          and lado_dos_vacio):
            return True

        #Todas las direcciones son estables, la casilla es estable.
        return False