示例#1
0
class Playground:
    projectiles_array = []

    def __init__(self, x_max, y_max, is_displayed, player1, player2):
        self.x_max = x_max
        self.y_max = y_max
        self.zones_x = 20
        self.zones_y = 20

        self.tank1 = Tank(5, randint(0, x_max), randint(0, y_max),
                          randint(0, 359), 10, 0)
        self.tank2 = Tank(5, randint(0, x_max), randint(0, y_max),
                          randint(0, 359), 10, 1)

        self.player1 = player1
        self.player2 = player2

        self.is_displayed = is_displayed

        if self.is_displayed:
            self.master = tk.Tk()
            canvas_width, canvas_height = 800, 800
            screen_width, screen_height = self.master.winfo_screenwidth(
            ), self.master.winfo_screenheight()
            x, y = (screen_width / 2) - (canvas_width / 2), (
                screen_height / 2) - (canvas_height / 2)
            self.master.geometry('%dx%d+%d+%d' %
                                 (canvas_width, canvas_height, x, y))
            self.visual_playground = tk.Canvas(self.master,
                                               width=canvas_width,
                                               height=canvas_height)
            self.hp = tk.Label(master=self.master, text="Hp: ")
            self.hp.pack()

    def draw_tanks_on_field(self):
        size = 10
        scale_x, scale_y = self.visual_playground.winfo_width(
        ) / self.x_max, self.visual_playground.winfo_height() / self.y_max
        x1, y1, dir1, x2, y2, dir2 = self.tank1.x * scale_x, self.tank1.y * scale_y, self.tank1.direction, self.tank2.x * scale_x, self.tank2.y * scale_y, self.tank2.direction
        points_tank1, points_tank2, delta_x, delta_y = [], [], [
            -size, size, size, -size
        ], [size, size, -size, -size]
        for i in range(0, 4, 1):
            rot_x1, rot_y1 = x1 + (delta_x[i] * cos(dir1) - delta_y[i] *
                                   sin(dir1)), y1 + (delta_x[i] * sin(dir1) +
                                                     delta_y[i] * cos(dir1))
            rot_x2, rot_y2 = x2 + (delta_x[i] * cos(dir2) - delta_y[i] *
                                   sin(dir2)), y2 + (delta_x[i] * sin(dir2) +
                                                     delta_y[i] * cos(dir2))
            points_tank1.append(rot_x1)
            points_tank1.append(rot_y1)
            points_tank2.append(rot_x2)
            points_tank2.append(rot_y2)
        self.visual_playground.create_polygon(points_tank1, fill='blue')
        self.visual_playground.create_polygon(points_tank2, fill='red')
        self.tank1 = Tank(0.1, randint(0, self.x_max), randint(0, self.y_max),
                          randint(0, 359), 0)
        self.tank2 = Tank(0.1, randint(0, self.x_max), randint(0, self.y_max),
                          randint(0, 359), 1)

    def draw_projectiles_on_field(self):
        scale_x, scale_y = self.visual_playground.winfo_width(
        ) / self.x_max, self.visual_playground.winfo_height() / self.y_max
        for i in [e for e in self.projectiles_array if e is not None]:
            self.visual_playground.create_oval(i.x * scale_x,
                                               i.y * scale_y,
                                               (i.x * scale_x) + 5,
                                               (i.y * scale_y) + 5,
                                               fill="red")

    def visualize_updated_playground(self):
        self.visual_playground.delete("all")
        self.draw_tanks_on_field()
        self.draw_projectiles_on_field()
        self.hp.config(text="Hp Tank1: " + str(self.tank1.hp) +
                       "          Hp Tank2: " + str(self.tank2.hp))
        self.visual_playground.update()
        self.visual_playground.pack()

    def _do_timestep(self, move_player1, move_player2):
        objects_to_remove = []
        for i in [e for e in self.projectiles_array if e is not None]:
            i.move_timestep(self.x_max, self.y_max)
            if not i.is_at_border(self.x_max, self.y_max):
                result = i.is_hitting_tank((self.tank1, self.tank2))
                if result[0] == True:
                    self.tank1.hp -= 10
                    #print('Projectile hit Tank 1')
                    return 'Projectile hit Tank 1'
                elif result[1] == True:
                    self.tank2.hp -= 10
                    #print('Projectile hit Tank 2')
                    return 'Projectile hit Tank 2'
            else:
                objects_to_remove.append(i)

        for i in objects_to_remove:
            self.projectiles_array.remove(i)

        self.tank1.move_timestep(self.x_max, self.y_max)
        self.tank2.move_timestep(self.x_max, self.y_max)

        player_1_result = self.player1.do_move(self.get_state(self.player1),
                                               move_player1)
        if player_1_result == 'right':
            self.tank1.turn_right()
        elif player_1_result == 'left':
            self.tank1.turn_left()
        elif player_1_result == 'shoot':
            projectile = self.tank1.shoot_projectile()
            if projectile != None:
                self.projectiles_array.append(projectile)

        player_2_result = self.player2.do_move(self.get_state(self.player2),
                                               move_player2)
        if player_2_result == 'right':
            self.tank2.turn_right()
        elif player_2_result == 'left':
            self.tank2.turn_left()
        elif player_2_result == 'shoot':
            projectile = self.tank2.shoot_projectile()
            if projectile != None:
                self.projectiles_array.append(projectile)

        return 'still playing'

    def reset_game(self):
        self.tank1 = Tank(5, randint(0, self.x_max), randint(0, self.y_max),
                          randint(0, 359), 10, 0)
        self.tank2 = Tank(5, randint(0, self.x_max), randint(0, self.y_max),
                          randint(0, 359), 10, 1)

    def start_game(self):
        self.reset_game()
        print('Start game')
        x = 0
        while x <= 1000:
            x += 1
            timestep_result = self._do_timestep(None, None)
            if self.is_displayed:
                time.sleep(0.05)
                thread_visual = threading.Thread(
                    target=self.visualize_updated_playground())
                thread_visual.daemon = True
                thread_visual.start()
            #if timestep_result != 'still playing':
            #    return timestep_result
            if self.tank1.hp == 0:
                return "Tank 2 won the game with " + str(self.tank2.hp) + " hp"
            elif self.tank2.hp == 0:
                return "Tank 1 won the game with " + str(self.tank1.hp) + " hp"
        if self.is_displayed:
            self.field_to_play_on.master.mainloop()

    def get_state(self, player):
        state = np.zeros((self.zones_x, self.zones_y))
        zone_x_tank1, zone_y_tank1, zone_x_tank2, zone_y_tank2 = ceil(
            (self.tank1.x / self.x_max) * self.zones_x), ceil(
                (self.tank1.y / self.y_max) * self.zones_y), ceil(
                    (self.tank2.x / self.x_max) * self.zones_x), ceil(
                        (self.tank2.y / self.y_max) * self.zones_y)
        if player == self.player1:
            state[zone_x_tank1 - 1, zone_y_tank1 - 1] = 1
            state[zone_x_tank2 - 1, zone_y_tank2 - 1] = -1
        elif player == self.player2:
            state[zone_x_tank1 - 1, zone_y_tank1 - 1] = -1
            state[zone_x_tank2 - 1, zone_y_tank2 - 1] = 1
        else:
            print('Player does not exist')

        for projectile in [e for e in self.projectiles_array if e is not None]:
            if projectile.x < self.x_max and projectile.y < self.y_max:
                zone_x_proj, zone_y_proj = ceil(
                    (projectile.x / self.x_max) * self.zones_x), ceil(
                        (projectile.y / self.y_max) * self.zones_y)
                if player == self.player1:
                    if projectile.tank_index == 0:
                        state[zone_x_proj - 1, zone_y_proj - 1] = 0.5
                    else:
                        state[zone_x_proj - 1, zone_y_proj - 1] = -0.5
                elif player == self.player2:
                    if projectile.tank_index == 0:
                        state[zone_x_proj - 1, zone_y_proj - 1] = 0.5
                    else:
                        state[zone_x_proj - 1, zone_y_proj - 1] = -0.5

        #return state.reshape(1, 20, 20)
        return state.reshape([1, 1, self.zones_x * self.zones_y])

    def reward(self, player):
        if player == self.player1:
            reward = (self.tank1.hp / 50.0) - (self.tank2.hp / 50.0)
        elif player == self.player2:
            reward = (self.tank2.hp / 50.0) - (self.tank1.hp / 50.0)
        else:
            print('Player does not exist')

        return reward

    def simulate_time_step(self, player, action):
        if player == self.player1:
            self._do_timestep(action, None)
        elif player == self.player2:
            self._do_timestep(None, action)
        else:
            print('Player does not exist')

        done = False
        if self.tank1.hp == 0 or self.tank2.hp == 0:
            done = True

        return self.get_state(player), self.reward(player), done