예제 #1
0
    def __generate_random_checks(self):
        min_x = Constants.border_padding()
        min_y = Constants.border_padding()
        max_x = Constants.world_x() - Constants.border_padding()
        max_y = Constants.world_y() - Constants.border_padding()
        min_dist_sq = Constants.check_spacing() * Constants.check_spacing()
        self.checkpoints = []

        num_checks = random.randrange(Constants.min_checks(),
                                      Constants.max_checks())
        while len(self.checkpoints) < num_checks:
            check = Vec2(random.randrange(min_x, max_x, 1),
                         random.randrange(min_y, max_y, 1))
            too_close = next((True for x in self.checkpoints
                              if (x - check).square_length() < min_dist_sq),
                             False)
            if not too_close:
                self.checkpoints.append(check)
예제 #2
0
 def play(self, pod: PodState) -> PlayOutput:
     return PlayOutput(
         Vec2(random() * Constants.world_x(), random() * Constants.world_y()),
         math.ceil(random() * Constants.max_thrust())
     )
예제 #3
0
파일: rewards.py 프로젝트: Kricket/tf-pods
import math
from typing import Tuple, Callable, List

from pod.ai.ai_utils import MAX_DIST
from pod.board import PodBoard
from pod.constants import Constants
from pod.util import PodState, clean_angle

#################################################
# Reward functions: signature is
# func(board, state) -> float
#################################################

RewardFunc = Callable[[PodBoard, PodState], float]
DIST_BASE = math.sqrt(Constants.world_x() * Constants.world_y())

def pgr(board: PodBoard, pod: PodState) -> float:
    """
    Pretty Good Reward
    Attempts to estimate the distance without using a SQRT calculation.
    """
    pod_to_check = board.checkpoints[pod.nextCheckId] - pod.pos
    prev_to_next_check = board.checkpoints[pod.nextCheckId] - board.get_check(pod.nextCheckId - 1)
    pod_dist_estimate = (math.fabs(pod_to_check.x) + math.fabs(pod_to_check.y)) / 2
    check_dist_estimate = (math.fabs(prev_to_next_check.x) + math.fabs(prev_to_next_check.y)) / 2
    dist_estimate = pod_dist_estimate / check_dist_estimate

    checks_hit = len(board.checkpoints) * pod.laps + pod.nextCheckId

    return 2*checks_hit - dist_estimate + 1
예제 #4
0
    def animate(self,
                max_turns: int = 1000,
                max_laps: int = 5,
                as_gif=False,
                filename='/tmp/pods',
                reset: bool = True,
                trail_len: int = 20,
                highlight_checks: bool = False,
                show_vel: bool = False,
                fps: int = 10):
        """
        Generate an animated GIF of the players running through the game
        :param show_vel Whether to draw a vector showing each Pod's velocity
        :param highlight_checks If true, a pod's next check will change to the pod's color
        :param trail_len Number of turns behind the pod to show its path
        :param as_gif If True, generate a GIF, otherwise an HTML animation
        :param max_turns Max number of turns to play
        :param max_laps Max number of laps for any player
        :param filename Where to store the generated file
        :param reset Whether to reset the state of each Player first
        :param fps Frames per second
        """
        if len(self.hist) < 1: self.record(max_turns, max_laps, reset)

        _prepare_size()
        self.__prepare_for_world()

        #########################################
        # Create the objects for display
        #########################################

        art = {
            'check': [],
            'pod': [],
            'color': [],
            'trails': [],
            'vel': [],
            'count':
            0,
            'log':
            JupyterLog(),
            'turnCounter':
            self.ax.text(-PADDING,
                         Constants.world_y() + PADDING,
                         'Turn 0',
                         fontsize=14)
        }

        fa = _get_field_artist()
        self.ax.add_artist(fa)

        for (idx, check) in enumerate(self.board.checkpoints):
            ca = self.__draw_check(check, idx)
            self.ax.add_artist(ca)
            art['check'].append(ca)

        for (idx, p) in enumerate(self.players):
            color = _gen_color(idx)
            pa = _get_pod_artist(p.pod, color)
            self.ax.add_artist(pa)
            art['pod'].append(pa)
            art['color'].append(color)
        plt.legend(art['pod'], self.labels, loc='lower right')

        if trail_len > 0:
            for i in range(len(self.players)):
                lc = LineCollection([], colors=art['color'][i])
                lc.set_segments([])
                lc.set_linestyle(':')
                self.ax.add_collection(lc)
                art['trails'].append(lc)

        if show_vel:
            for p in self.players:
                xy = _vel_coords(p.pod)
                line = self.ax.plot(xy[0], xy[1])[0]
                art['vel'].append(line)

        all_updates = [
            fa, *art['check'], *art['pod'], *art['trails'], *art['vel'],
            art['turnCounter']
        ]

        #########################################
        # Define the animation function
        #########################################

        def do_animate(frame_idx: int):
            art['log'].replace("Drawing frame {}".format(art['count']))
            art['count'] += 1

            check_colors = [
                'royalblue' for _ in range(len(self.board.checkpoints))
            ]
            frame_data = self.hist[frame_idx]

            # Update the pods
            for (p_idx, player_log) in enumerate(frame_data):
                pod = player_log['pod']
                theta1, theta2, center = _pod_wedge_info(pod)
                art['pod'][p_idx].set_center((center.x, center.y))
                art['pod'][p_idx].set_theta1(theta1)
                art['pod'][p_idx].set_theta2(theta2)
                art['pod'][p_idx]._recompute_path()  # pylint: disable=protected-access

                check_colors[pod.nextCheckId] = art['color'][p_idx]

                # Update the velocities
                if show_vel:
                    xy = _vel_coords(pod)
                    art['vel'][p_idx].set_xdata(xy[0])
                    art['vel'][p_idx].set_ydata(xy[1])

            # Update the trails
            if frame_idx > 0 and trail_len > 0:
                for p_idx in range(len(self.players)):
                    line = _to_line(self.hist[frame_idx - 1][p_idx]['pod'].pos,
                                    frame_data[p_idx]['pod'].pos)
                    segs = art['trails'][p_idx].get_segments() + [line]
                    art['trails'][p_idx].set_segments(segs[-trail_len:])

            # Update the check colors
            if highlight_checks:
                for col, check_art in zip(check_colors, art['check']):
                    check_art.set_color(col)

            # Update the turn counter
            art['turnCounter'].set_text('Turn ' + str(frame_idx))

            return all_updates

        #########################################
        # Create the animation
        #########################################

        anim = FuncAnimation(
            plt.gcf(),
            do_animate,
            frames=len(self.hist),
        )
        plt.close(self.fig)

        if as_gif:
            if not filename.endswith(".gif"): filename = filename + ".gif"
            anim.save(filename, writer=PillowWriter(fps=fps))
            return Image(filename=filename)
        else:
            if not filename.endswith(".html"): filename = filename + ".html"
            anim.save(filename,
                      writer=HTMLWriter(fps=fps,
                                        embed_frames=True,
                                        default_mode='loop'))
            path = Path(filename)
            return HTML(path.read_text())
예제 #5
0
 def __prepare_for_world(self):
     self.fig = plt.figure()
     self.ax = plt.axes(xlim=(-PADDING, Constants.world_x() + PADDING),
                        ylim=(-PADDING, Constants.world_y() + PADDING))
     self.ax.invert_yaxis()
예제 #6
0
파일: util.py 프로젝트: Kricket/tf-pods
 def random() -> 'PodState':
     return PodState(pos=Vec2.random(Constants.world_x(),
                                     Constants.world_y()),
                     vel=UNIT.rotate(2 * math.pi * random()) *
                     (random() * Constants.max_vel()),
                     angle=2 * math.pi * random())
예제 #7
0
파일: podagent.py 프로젝트: Kricket/tf-pods
 def _get_reward(self) -> int:
     reward = Constants.world_x() * Constants.world_y()
     reward += self._player.pod.nextCheckId * 10000
     reward -= (self._world.checkpoints[self._player.pod.nextCheckId] -  self._player.pod.pos).square_length()
     return np.asarray(reward, dtype=np.float32)
예제 #8
0
파일: ai_utils.py 프로젝트: Kricket/tf-pods
import math
from typing import List

import numpy as np
from pod.constants import Constants
from pod.controller import Controller
from pod.util import PodState, clean_angle
from vec2 import Vec2, UNIT

# Distance to use for scaling inputs
MAX_DIST = Vec2(Constants.world_x(), Constants.world_y()).length()


def gen_pods(checks: List[Vec2], pos_angles: List[float],
             pos_dists: List[float], angles: List[float],
             vel_angles: List[float], vel_mags: List[float]):
    """
    Generate pods in various states
    :param checks: Checkpoints around which to generate
    :param pos_angles: Angles from check to pod
    :param pos_dists: Distances from check to pod
    :param angles: Orientations of pods. This will be rotated so that 0 points toward the check!
    :param vel_angles: Angles of velocity. Also rotated so that 0 points toward the check.
    :param vel_mags: Magnitudes of velocity
    :return: One pod for each combination of parameters
    """
    relative_poss = [
        UNIT.rotate(ang) * dist for ang in pos_angles for dist in pos_dists
    ]
    relative_vels = [
        UNIT.rotate(ang) * mag for ang in vel_angles for mag in vel_mags