main

this is the engine of the game
mail@pastecode.io avatar
unknown
python
2 years ago
22 kB
18
Indexable
import blessed, math, os, time

from ai_agent import get_AI_orders

def file_to_data_structure(path):
    if not os.path.exists(path):
        return "This path doesn't exist"

    with open(path) as file:
        lines = file.readlines()

    dimension_board = [int(x) for x in lines[1].split()]

    home_1, home_2 = lines[3].split(), lines[4].split()
    player_1_pos, player_2_pos = [int(home_1[1]) - 1, int(home_1[2]) - 1], [int(home_2[1]) - 1, int(home_2[2]) - 1]
    if home_1[0] != "1":
        player_1_pos, player_2_pos = player_2_pos, player_1_pos

    player_1, player_2 = [500, [], player_1_pos], [500, [], player_2_pos]

    game_board = [[{"case_color": "#EEEEEE", "emoji": "null", "nb_magic": "null", "type": "empty"} for _ in
                   range(dimension_board[0])] for _ in range(dimension_board[1])]
    for magic in lines[6:]:
        magic_list = list(map(int, magic.split()))
        if magic_list[0] > dimension_board[0] or magic_list[1] > dimension_board[1]:
            print("This box can't be an element of the board")
        else:
            game_board[magic_list[1] - 1][magic_list[0] - 1] = {"case_color": "#EEEEEE", "emoji": "🪄",
                                                                "nb_magic": magic_list[2], "type": "magic"}

    return dimension_board, player_1, player_2, game_board

def is_neighbour(pos,new_position):
    possible_positions = ([pos[0],pos[1]],[pos[0]+1,pos[1]+1],[pos[0]+1,pos[1]],[pos[0]+1,pos[1]-1],[pos[0],pos[1]-1],[pos[0],pos[1]+1],[pos[0]-1,pos[1]-1],[pos[0]-1,pos[1]],[pos[0]-1,pos[1]+1])
    if new_position in possible_positions:
       return 1
    else:
        return 0

def coloring_box(j, i, box):
    # the terminal of where we will play the game
    term = blessed.Terminal()

    # box size
    box_width = 6
    box_height = 3

    # getting the content of the box

    # get the color from the content of the box and transform it from Hexadecimal to RGB value
    box_color_rgb = hex_to_rgb(str(box["case_color"]))

    # get the type
    box_type = str(box["type"])

    # get the number of magic
    box_nb_magic = str(box["nb_magic"])

    # the right coordonate position of the box
    x = box_width * j

    # the bottom coordonate position of the box
    y = box_height * i

    # point the cursor in the right bottom of the box
    print(term.move_xy(x, y))

    # coloring all the units of the box

    # horizintal units
    for unit_x in range((x + (j * 2) - box_width) + 2, x + (j * 2) + 2):

        # vertical units
        for unit_y in range((y + i - box_height) + 1, y + i + 1):
            # coloring the unit
            print(term.move_xy(unit_x, unit_y) + term.on_color_rgb(box_color_rgb[0], box_color_rgb[1],
                                                                   box_color_rgb[2]) + ' ' + term.normal, flush=True)

    # insert emojis depending to the type of the box

    # if the box is ghost box
    if box_type == "ghost":

        # insert ghost emoji
        print(
            term.move_xy((x + (j * 2) - box_width) + 4, (y + i - box_height) + 2) + term.on_color_rgb(box_color_rgb[0],
                                                                                                      box_color_rgb[1],
                                                                                                      box_color_rgb[
                                                                                                          2]) + "👻" + term.normal,
            flush=True)

        # if number of magic of the ghost is more than 99 and magic points if exists
        if int(box_nb_magic) > 99:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6 - 1, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(255, 255, 255) + str(
                box_nb_magic) + term.normal, flush=True)

        # if number of magic is less than 99
        else:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(255, 255, 255) + str(
                box_nb_magic) + term.normal, flush=True)

    # if the box is home boxhome
    elif box_type == "home":

        # insert home emoji
        print(
            term.move_xy((x + (j * 2) - box_width) + 4, (y + i - box_height) + 2) + term.on_color_rgb(box_color_rgb[0],
                                                                                                      box_color_rgb[1],
                                                                                                      box_color_rgb[
                                                                                                          2]) + "⌂" + term.normal,
            flush=True)

    # if the box is magic box
    elif box_type == "magic":

        # insert ghost emoji
        print(
            term.move_xy((x + (j * 2) - box_width) + 4, (y + i - box_height) + 2) + term.on_color_rgb(box_color_rgb[0],
                                                                                                      box_color_rgb[1],
                                                                                                      box_color_rgb[
                                                                                                          2]) + "🪄" + term.normal,
            flush=True)

        # if number of magic is more than 99
        if int(box_nb_magic) > 99:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6 - 1, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(41, 52, 98) + str(
                box_nb_magic) + term.normal, flush=True)

        # if number of magic is less than 99
        else:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(41, 52, 98) + str(
                box_nb_magic) + term.normal, flush=True)

    # if the box type is a fusion between magic and ghost
    elif box_type == "magic+ghost":

        # split nb_magic points of the magic and nb_magic points of the ghost
        box_nb_magic = box_nb_magic.split("+")

        # insert the nb_maigc_points of the magic
        print(
            term.move_xy((x + (j * 2) - box_width) + 2, (y + i - box_height) + 1) + term.on_color_rgb(box_color_rgb[0],
                                                                                                      box_color_rgb[1],
                                                                                                      box_color_rgb[
                                                                                                          2]) + term.color_rgb(
                255, 255, 255) + str(box_nb_magic[0]) + term.normal, flush=True)

        # insert ghost emoji
        print(
            term.move_xy((x + (j * 2) - box_width) + 4, (y + i - box_height) + 2) + term.on_color_rgb(box_color_rgb[0],
                                                                                                      box_color_rgb[1],
                                                                                                      box_color_rgb[
                                                                                                          2]) + "👻" + term.normal,
            flush=True)

        # if number of magic of the ghost if more than 99 and magic points if exists
        if int(box_nb_magic[1]) > 99:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6 - 1, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(255, 255, 255) + str(
                box_nb_magic[1]) + term.normal, flush=True)

        # if number of magic of the ghost if less than 99
        else:

            # insert the number of magic
            print(term.move_xy((x + (j * 2) - box_width) + 6, (y + i - box_height) + 3) + term.on_color_rgb(
                box_color_rgb[0], box_color_rgb[1], box_color_rgb[2]) + term.color_rgb(255, 255, 255) + str(
                box_nb_magic[1]) + term.normal, flush=True)


    # if the box is empty box
    else:

        # don't insert anything
        print("")


def hex_to_rgb(value: str) -> tuple:

    # Remove the '#' character from the value of color
    value = value.lstrip('#')

    # Convert the hex color code to an RGB tuple
    red = int(value[0:2], 16)
    green = int(value[2:4], 16)
    blue = int(value[4:6], 16)

    return red, green, blue

def decorate_game_board(game_board):
    for i, line in enumerate(game_board, start=1):
        for j, box_dict in enumerate(line, start=1):
            box = dict(box_dict)
            coloring_box(j, i, box)


def display_game_informations(dimension_board, player_1, player_2, nb_turn):
    # initialize blessed Terminal
    term = blessed.Terminal()

    # set box height and height space
    box_height = 3
    height_space = 1

    # display player 1 information
    player_1_text = 'Player 1 : {}'.format(player_1[0])
    print(term.move_xy(4, ((box_height + height_space) * dimension_board[1] + 2)) +
          term.on_color_rgb(214, 28, 78) + player_1_text + term.normal, flush=True, end="")

    # display player 2 information
    player_2_text = 'Player 2 : {}'.format(player_2[0])
    print(term.move_xy(23, ((box_height + height_space) * dimension_board[1] + 2)) +
          term.on_color_rgb(41, 52, 98) + player_2_text + term.normal, flush=True,end="")

    # display turn information
    turn_text = 'Turn : {}'.format(nb_turn)
    print(term.move_xy(42, ((box_height + height_space) * dimension_board[1] + 2)) +
          term.on_color_rgb(255, 255, 255) + term.color_rgb(41, 52, 98) + turn_text + term.normal, flush=True)


def change_player_nb_magic_points(player_info,nb_magic):
  player_info[0] += nb_magic
  return player_info

def change_ghost_nb_magic_points(game_board, ghost_position, nb_magic):
    box_info = game_board[ghost_position[1]][ghost_position[0]]
    current_points = box_info.get("nb_magic", 0)
    if isinstance(current_points, str) and "+" in current_points:
        magic_p, current_points = current_points.split("+")
        result = int(current_points) + nb_magic
        new_points = f"{magic_p}+{result}"
    else:
        new_points = str(int(current_points) + nb_magic)

    game_board[ghost_position[1]][ghost_position[0]] = {
        "case_color": box_info["case_color"],
        "emoji": box_info["emoji"],
        "type": "ghost",
        "nb_magic": new_points,
    }
    return game_board

def is_empty_box(game_board,box_position):
    
    case = game_board[box_position[1]][box_position[0]]
    if case["type"] not in ["ghost"]:
        return 1
    else:
        return 0
def move_ghost(game_board, player_info, current_position, new_position):
    def get_box(position):
        return game_board[position[1]][position[0]]

    def set_box(position, box):
        game_board[position[1]][position[0]] = box

    current_box = get_box(current_position)
    new_box = get_box(new_position)

    if current_box["type"] not in ["ghost", "magic+ghost"]:
        return

    if is_empty_box(game_board, new_position) == 0 and not (current_box["type"] in ["ghost", "magic+ghost"] and new_box["type"] == "magic"):
        return

    if is_neighbour(current_position, new_position) == 0:
        return

    if current_box["type"] == "magic+ghost":
        magic_points = str(current_box["nb_magic"]).split("+")
        magic_box = {"case_color": "#EEEEEE", "emoji": "🪄", "nb_magic": magic_points[0], "type": "magic"}
        ghost_box = {"case_color": current_box["case_color"], "emoji": current_box["emoji"], "nb_magic": magic_points[1], "type": "ghost"}

        if new_box["type"] == "magic":
            new_nb_magic = str(new_box["nb_magic"]) + "+" + str(current_box["nb_magic"])
            new_type = str(new_box["type"]) + "+" + str(current_box["type"])
        else:
            new_nb_magic = current_box["nb_magic"]
            new_type = current_box["type"]

        set_box(new_position, {"case_color": ghost_box["case_color"], "emoji": ghost_box["emoji"], "nb_magic": new_nb_magic, "type": new_type})
        set_box(current_position, magic_box)

    else:
        if new_box["type"] == "magic":
            new_nb_magic = str(new_box["nb_magic"]) + "+" + str(current_box["nb_magic"])
            new_type = new_box["type"] + "+" + current_box["type"]
        else:
            new_nb_magic = current_box["nb_magic"]
            new_type = current_box["type"]

        set_box(new_position, {"case_color": current_box["case_color"], "emoji": current_box["emoji"], "nb_magic": new_nb_magic, "type": new_type})
        set_box(current_position, {"case_color": "#EEEEEE", "emoji": "null", "nb_magic": "null", "type": "empty"})

    ghosts = player_info[1]
    ghost_index = next((i for i, g in enumerate(ghosts) if g[1:3] == current_position), None)

    if ghost_index is not None:
        ghosts[ghost_index][1:3] = new_position
        player_info[1] = ghosts

    coloring_box(current_position[0] + 1, current_position[1] + 1, get_box(current_position))
    coloring_box(new_position[0] + 1, new_position[1] + 1, get_box(new_position))

    return game_board, player_info
            
def create_ghost(game_board, player_info, color):
    magic_points = int(player_info[0])
    if magic_points >= 300:
        x, y = player_info[2]
        if is_empty_box(game_board, (x, y)):
            new_ghost = [len(player_info[1]), x, y]
            player_info[1].append(new_ghost)
            game_board[y][x] = {
                "case_color": color,
                "emoji": "👻",
                "type": "ghost",
                "nb_magic": 100,
            }
            change_player_nb_magic_points(player_info, -300)
        else:
            print("The case is already full. You can't create a ghost here.")
    return game_board, player_info

def is_ghost_exists(game_board,ghost):
  return game_board[ ghost[1] ][ ghost[0] ] == "ghost"


def attack(game_board, ghost_attacker, ghost_attacked, player_attacker, player_attacked):
    if not is_ghost_exists(game_board, ghost_attacked):
        return game_board, player_attacker, player_attacked

    if not is_neighbour(ghost_attacker, ghost_attacked):
        return game_board, player_attacker, player_attacked

    change_ghost_nb_magic_points(game_board, ghost_attacked, -10)
    coloring_box(ghost_attacked[0] + 1, ghost_attacked[1] + 1, game_board[ghost_attacked[1]][ghost_attacked[0]])
    change_player_nb_magic_points(player_attacker, 10)

    if not is_dead(game_board, ghost_attacked):
        return game_board, player_attacker, player_attacked

    game_board[ghost_attacked[1]][ghost_attacked[0]] = {"case_color": "#EEEEEE", "emoji": "null", "nb_magic": "null",
                                                        "type": "empty"}
    coloring_box(ghost_attacked[0] + 1, ghost_attacked[1] + 1, game_board[ghost_attacked[1]][ghost_attacked[0]])

    for i, ghost in enumerate(player_attacked[1]):
        if ghost[1:] == ghost_attacked:
            del player_attacked[1][i]
            break

    return game_board, player_attacker, player_attacked


def execute_orders(orders, game_board, player_info, current_player, second_player):
    if not orders:
        return game_board, player_info

    orders_list = orders.strip().split()

    for order in orders_list:
        try:
            if order == "ghost":
                color = "#D61C4E" if current_player == 1 else "#293462"
                create_ghost(game_board, player_info, color)
            else:
                order_parts = order.split(":")
                ghost_pos = tuple(map(int, order_parts[0].split("-")))
                operation = order_parts[1][0]
                target_pos = tuple(map(int, order_parts[1][1:].split("-")))
                box_info = game_board[ghost_pos[1]-1][ghost_pos[0]-1]
                if operation == "x":
                    attack(game_board, ghost_pos, target_pos, player_info, second_player)
                elif operation == "@":
                    move_ghost(game_board, player_info, ghost_pos, target_pos)
                elif operation == "$":
                    nb_magic, recolting_magic = map(int, box_info["nb_magic"].split("+"))
                    player_info = change_player_nb_magic_points(player_info, nb_magic)
                    game_board[ghost_pos[1]-1][ghost_pos[0]-1] = {
                        "case_color": box_info["case_color"],
                        "emoji": box_info["emoji"],
                        "type": "ghost",
                        "nb_magic": str(recolting_magic),
                    }
                    coloring_box(ghost_pos[0], ghost_pos[1], game_board[ghost_pos[1]-1][ghost_pos[0]-1])
                elif operation == "+":
                    nb_magic = int(box_info["nb_magic"])
                    game_board[ghost_pos[1]-1][ghost_pos[0]-1]["nb_magic"] = str(nb_magic + int(order_parts[1][1:]))
                    player_info = change_player_nb_magic_points(player_info, -2 * int(order_parts[1][1:]))

        except:
            pass

    decorate_game_board(game_board)
    return game_board, player_info
  
def is_dead(game_board,ghost_coordonate):
        return int(game_board[ghost_coordonate[1]][ghost_coordonate[0]]["nb_magic"]) <= 0


def is_winner(player_1 , player_2):
        if player_1[0] > player_2[0]:
           return 1
        elif player_1[0] < player_2[0]:
           return 2
        return 0

def change_player(player):
   if player == 1 :
      return 2 
   else :
      return 1

def one_order_by_ghost(orders):
   used_ghosts = []
   orders = str(orders).split()
   cpt = 0
   for order in orders:
      if order == "ghost":
         cpt += 1
      elif ":" in order:
         order_sides = order.split(":")
         if order_sides[0] in used_ghosts :
            del orders[cpt]
         else :
            if "@" in order_sides[1]:
               right_side = order_sides[1]
               used_ghosts.append(right_side[1:])
            else:
               used_ghosts.append(order_sides[0])
            cpt += 1
   orders_str = ""
   for order in orders:
      orders_str += str(order) + " "
   return orders_str


def play_game(map_path, type_1, type_2):
    term = blessed.Terminal()
    print(term.clear())

    nb_turns = 1
    player_1_color = "#D61C4E"
    player_2_color = "#293462"

    dimension_board, player_1, player_2, game_board = file_to_data_structure(map_path)
    player_1[0] = 500
    player_2[0] = 500

    decorate_game_board(game_board)
    time.sleep(1)

    game_board, player_1 = create_ghost(game_board, player_1, player_1_color)
    decorate_game_board(game_board)
    time.sleep(1)

    game_board, player_2 = create_ghost(game_board, player_2, player_2_color)
    decorate_game_board(game_board)
    time.sleep(1)

    current_player = 1
    while nb_turns <= 200 and len(player_1[1]) > 0 and len(player_2[1]) > 0:
        print(term.clear())
        decorate_game_board(game_board)
        display_game_informations(
            dimension_board, player_1, player_2, nb_turns
        )

        if type_1 == "human" and type_2 == "human":
            if current_player == 1:
                orders = input("Player 1: enter the orders please: ")
                orders = one_order_by_ghost(orders)
                execute_orders(orders, game_board, player_1, 1, player_2)
            else:
                orders = input("Player 2: enter the orders please: ")
                orders = one_order_by_ghost(orders)
                execute_orders(orders, game_board, player_2, 2, player_1)

            display_game_informations(
                dimension_board, player_1, player_2, nb_turns
            )
            current_player = change_player(current_player)
        elif type_1 == "human" and type_2 == "ai":
            if current_player == 1:
                orders = get_AI_orders(game_board, player_2, 2)
                input("Order taken")
                orders = one_order_by_ghost(orders)
                execute_orders(orders, game_board, player_2, 2, player_1)
            else:
                orders = input("Player 1: enter the orders please: ")
                orders = one_order_by_ghost(orders)
                execute_orders(orders, game_board, player_1, 1, player_2)

            display_game_informations(
                dimension_board, player_1, player_2, nb_turns
            )
            current_player = change_player(current_player)

        change_player_nb_magic_points(player_1, 10 + len(player_1[1]))
        change_player_nb_magic_points(player_2, 10 + len(player_2[1]))
        nb_turns += 1
        time.sleep(1)

    if nb_turns > 200:
        winner_number = is_winner(player_1, player_2)
        if winner_number == 1:
            winner_text = "the Player 1 is winner 🏆"
        elif winner_number == 2:
            winner_text = "the Player 2 is winner 🏆"
        print(winner_text)

play_game("./map.txt","human","human")