コード例 #1
0
ファイル: game.py プロジェクト: MIECT-UA/iia-ia-pacman
class Game:
    def __init__(self, mapfile, n_ghosts=GHOSTS, lives=LIVES, timeout=TIMEOUT):
        logger.info("Game({}, {}, {})".format(mapfile, n_ghosts, lives))
        self._running = False
        self._timeout = timeout
        self._state = {}
        self._n_ghosts = n_ghosts
        self._initial_lives = lives
        self.map = Map(mapfile)

        self._highscores = []
        if os.path.isfile(mapfile + ".score"):
            with open(mapfile + ".score", 'r') as infile:
                self._highscores = json.load(infile)

    def info(self):
        return json.dumps({
            "map": self.map.filename,
            "ghosts": self._n_ghosts,
            "fps": GAME_SPEED,
            "timeout": TIMEOUT,
            "lives": LIVES,
            "points": {
                "energy": POINT_ENERGY,
                "boost": POINT_BOOST,
                "ghost": POINT_GHOST,
                "time_bonus": POINT_TIME_BONUS
            },
            "boost_timeout": BOOST_TIMEOUT,
            "highscores": self.highscores,
        })

    def consume(self, pos):
        """Update map at position."""
        if pos in self._energy:
            self._energy.remove(pos)
            return Tiles.ENERGY
        if pos in self._boost:
            self._boost.remove(pos)
            return Tiles.BOOST

    @property
    def running(self):
        return self._running

    @property
    def score(self):
        return self._score

    @property
    def highscores(self):
        return self._highscores

    def start(self, player_name):
        logger.debug("Reset world")
        self._player_name = player_name
        self._running = True

        self.map = Map(self.map.filename)
        self._step = 0
        self._ghosts = [Ghost(self.map) for g in range(0, self._n_ghosts)]
        self._pacman = self.map.pacman_spawn
        self._energy = self.map.energy
        self._boost = self.map.boost
        self._lastkeypress = "d"
        self._score = INITIAL_SCORE
        self._lives = self._initial_lives

    def stop(self):
        logger.info("GAME OVER")
        self.save_highscores()
        self._running = False

    def quit(self):
        logger.debug("Quit")
        self._running = False

    def save_highscores(self):
        #update highscores
        logger.debug("Save highscores")
        self._highscores.append((self._player_name, self.score))
        self._highscores = sorted(self._highscores,
                                  key=lambda s: -1 * s[1])[:MAX_HIGHSCORES]

        with open(self.map._filename + ".score", 'w') as outfile:
            json.dump(self._highscores, outfile)

    def keypress(self, key):
        self._lastkeypress = key

    def update_pacman(self):
        self._pacman = self.map.calc_pos(self._pacman, self._lastkeypress)
        c = self.consume(self._pacman)
        if c == Tiles.ENERGY:
            self._score += POINT_ENERGY
        elif c == Tiles.BOOST:
            self._score += POINT_BOOST
            for g in self._ghosts:
                g.make_zombie(BOOST_TIMEOUT)

        if len(self._energy) + len(self._boost) == 0:
            logger.info("Level completed")
            self._score += ((self._timeout - self._step) //
                            TIME_BONUS_STEPS) * POINT_TIME_BONUS
            self.stop()

    def collision(self):
        for g in self._ghosts:
            if g.pos == self._pacman and self._running:
                if g.zombie:
                    self._score += POINT_GHOST
                    g.respawn()
                else:
                    logger.info("PACMAN has died")
                    if self._lives:
                        self._lives -= 1
                        self._pacman = self.map.pacman_spawn
                        g.respawn()
                    if not self._lives:
                        self.stop()
                        return

    async def next_frame(self):
        await asyncio.sleep(1. / GAME_SPEED)

        if not self._running:
            logger.info("Waiting for player 1")
            return

        self._step += 1
        if self._step == self._timeout:
            self.stop()

        if self._step % 100 == 0:
            logger.debug("[{}] SCORE {} - LIVES {}".format(
                self._step, self._score, self._lives))

        self.update_pacman()
        self.collision()

        for ghost in self._ghosts:
            ghost.update(self._state)
        self.collision()

        self._state = {
            "step": self._step,
            "player": self._player_name,
            "score": self._score,
            "lives": self._lives,
            "pacman": self._pacman,
            "ghosts":
            [(g.pos, g.zombie, g.zombie_timeout) for g in self._ghosts],
            "energy": self._energy,
            "boost": self._boost,
        }

    @property
    def state(self):
        return json.dumps(self._state)
コード例 #2
0
async def agent_loop(server_address="localhost:8000", agent_name="student"):
    async with websockets.connect(
            "ws://{}/player".format(server_address)) as websocket:
        # Receive information about static game properties
        await websocket.send(json.dumps({"cmd": "join", "name": agent_name}))
        msg = await websocket.recv()
        game_properties = json.loads(msg)

        _map = Map(game_properties['map'])

        area = _map.size[0] * _map.size[1]
        GHOST_PENALIZATION = area
        BOOST_PENALIZATION = max(_map.size)
        GHOST_CHASE_DISTANCE = 3
        N_GOALS = 4
        ZOMBIE_SPEED = .5

        #initialize agent properties
        key = None
        cur_x, cur_y = None, None
        ptarget = None
        while True:
            r = await websocket.recv()
            state = json.loads(r)
            ppos = tuple(state['pacman'])
            lenergy = [tuple(x) for x in state['energy']]
            lghosts = [tuple(x[0]) for x in state['ghosts'] if not x[1]]
            lzombies = [(tuple(x[0]), x[2]) for x in state['ghosts'] if x[1]]
            lboosts = [tuple(x) for x in state['boost']]
            if ptarget is None:
                ptarget = ppos

            if not state['lives'] or (len(lenergy) == 0 and len(lboosts) == 0):
                logger.info("GAME OVER")
                return

            logger.debug("Lives = %d", state['lives'])

            # Create new search problem
            targets = select_target(ppos, lenergy, lghosts, lzombies, lboosts,
                                    ptarget, tuple(_map.ghost_spawn),
                                    GHOST_CHASE_DISTANCE, ZOMBIE_SPEED)

            # Create multiple goals
            goals = []
            for i in range(min(len(targets), N_GOALS)):
                goals += [(targets[i], None)]

            # Search all goals at the same time
            if len(lghosts) == 0 and len(lzombies) == 0:
                st = SearchTree(
                    SearchProblem(PacPath(_map, lghosts, lboosts),
                                  (ppos, None), goals))
            else:
                st = SearchTree(
                    SearchProblem(
                        PacPath(_map, lghosts, lboosts, GHOST_PENALIZATION,
                                BOOST_PENALIZATION), (ppos, None), goals))
            path = st.search()

            # When trapped by ghosts take a valid step
            if path is None:
                logger.debug("No Path found...")
                if direction is None:
                    for d in ['w', 's', 'a', 'd']:
                        npos = _map.calc_pos(ppos, d)
                        if npos != ppos:
                            direction = d
                            target = npos
                            cost = 1
            else:
                target = path[1][-1][0]
                direction = path[1][1][1]
                cost = path[0]

            logger.debug("Target = %s Direction = %s (Cost = %f)", target,
                         direction, cost)
            #send new key
            await websocket.send(json.dumps({"cmd": "key", "key": direction}))
            ptarget = target
コード例 #3
0
class Game:
    def __init__(self, level=1, lives=LIVES, timeout=TIMEOUT, size=MAP_SIZE):
        logger.info(f"Game(level={level}, lives={lives})")
        self.initial_level = level
        self._running = False
        self._timeout = timeout
        self._score = 0
        self._state = {}
        self._initial_lives = lives
        self.map = Map(size=size, empty=True)
        self._enemies = []

    def info(self):
        return {
            "size": self.map.size,
            "map": self.map.map,
            "fps": GAME_SPEED,
            "timeout": TIMEOUT,
            "lives": LIVES,
            "score": self.score,
        }

    @property
    def running(self):
        return self._running

    @property
    def score(self):
        return self._score

    def start(self, player_name):
        logger.debug("Reset world")
        self._player_name = player_name
        self._running = True
        self._score = INITIAL_SCORE
        self._bomberman = Bomberman(self.map.bomberman_spawn,
                                    self._initial_lives)

        self.next_level(self.initial_level)

    def stop(self):
        logger.info("GAME OVER")
        self._running = False

    def next_level(self, level):
        if level > len(LEVEL_ENEMIES):
            logger.info("You WIN!")
            self.stop()
            return

        logger.info("NEXT LEVEL")
        self.map = Map(level=level,
                       size=self.map.size,
                       enemies=len(LEVEL_ENEMIES[level]))
        self._bomberman.respawn()
        self._step = 0
        self._bombs = []
        self._powerups = []
        self._bonus = []
        self._exit = []
        self._lastkeypress = ""
        self._enemies = [
            t(p) for t, p in zip(LEVEL_ENEMIES[level], self.map.enemies_spawn)
        ]
        logger.debug(self._enemies)

    def quit(self):
        logger.debug("Quit")
        self._running = False

    def keypress(self, key):
        self._lastkeypress = key

    def update_bomberman(self):
        try:
            if self._lastkeypress.isupper():
                # Parse action
                if self._lastkeypress == "A" and len(self._bombs) > 0:
                    self._bombs[0].detonate(
                    )  # always detonate the oldest bomb
                elif (self._lastkeypress == "B" and len(self._bombs) <
                      self._bomberman.powers.count(Powerups.Bombs) + 1):
                    self._bombs.append(
                        Bomb(
                            self._bomberman.pos,
                            self.map,
                            MIN_BOMB_RADIUS + self._bomberman.flames(),
                            detonator=Powerups.Detonator
                            in self._bomberman.powers,
                        ))  # must be dependent of powerup
            else:
                # Update position
                new_pos = self.map.calc_pos(
                    self._bomberman.pos, self._lastkeypress,
                    self._bomberman.wallpass)  # don't bump into stones/walls
                if self._bomberman.bombpass or new_pos not in [
                        b.pos for b in self._bombs
                ]:  # don't pass over bombs
                    self._bomberman.pos = new_pos
                for pos, _type in self._powerups:  # consume powerups
                    if new_pos == pos:
                        self._bomberman.powerup(_type)
                        self._powerups.remove((pos, _type))

        except AssertionError:
            logger.error("Invalid key <%s> pressed. Valid keys: w,a,s,d A B",
                         self._lastkeypress)
        finally:
            self._lastkeypress = ""  # remove inertia

        if len(self._enemies) == 0 and self._bomberman.pos == self._exit:
            logger.info(f"Level {self.map.level} completed")
            #self._score += self._timeout - self._step
            self.next_level(self.map.level + 1)

    def kill_bomberman(self):
        logger.info(f"bomberman has died on step: {self._step}")
        self._bomberman.kill()
        logger.debug(f"bomberman has now {self._bomberman.lives} lives")
        if self._bomberman.lives > 0:
            logger.debug("RESPAWN")
            self._bomberman.respawn()
        else:
            self.stop()

    def collision(self):
        for e in self._enemies:
            if e.pos == self._bomberman.pos:
                self.kill_bomberman()
                e.respawn()

    def explode_bomb(self):
        for bomb in self._bombs[:]:
            bomb.update()
            if bomb.exploded():
                logger.debug("BOOM")
                if bomb.in_range(
                        self._bomberman) and not self._bomberman.flamepass:
                    self.kill_bomberman()

                for wall in self.map.walls[:]:
                    if bomb.in_range(wall):
                        logger.debug(f"Destroying wall @{wall}")
                        self.map.remove_wall(wall)
                        if self.map.exit_door == wall:
                            self._exit = wall
                        if self.map.powerup == wall:
                            self._powerups.append(
                                (wall, LEVEL_POWERUPS[self.map.level]))

                for enemy in self._enemies[:]:
                    if bomb.in_range(enemy):
                        logger.debug(f"killed enemy @{enemy}")
                        self._score += enemy.points()
                        self._enemies.remove(enemy)

                self._bombs.remove(bomb)

    async def next_frame(self):
        await asyncio.sleep(1.0 / GAME_SPEED)

        if not self._running:
            logger.info("Waiting for player 1")
            return

        self._step += 1
        if self._step == self._timeout:
            self.stop()

        if self._step % 100 == 0:
            logger.debug(
                f"[{self._step}] SCORE {self._score} - LIVES {self._bomberman.lives}"
            )

        self.explode_bomb()
        self.update_bomberman()
        self.collision()

        if (self._step % (self._bomberman.powers.count(Powerups.Speed) + 1) ==
                0):  # increase speed of bomberman by moving enemies less often
            for enemy in self._enemies:
                enemy.move(self.map, self._bomberman, self._bombs,
                           self._enemies)
            self.collision()

        self._state = {
            "level":
            self.map.level,
            "step":
            self._step,
            "timeout":
            self._timeout,
            "player":
            self._player_name,
            "score":
            self._score,
            "lives":
            self._bomberman.lives,
            "bomberman":
            self._bomberman.pos,
            "bombs": [(b.pos, b.timeout, b.radius) for b in self._bombs],
            "enemies": [{
                "name": str(e),
                "id": str(e.id),
                "pos": e.pos
            } for e in self._enemies],
            "walls":
            self.map.walls,
            "powerups": [(p, Powerups(n).name) for p, n in self._powerups],
            "bonus":
            self._bonus,
            "exit":
            self._exit,
        }

    @property
    def state(self):
        # logger.debug(self._state)
        return json.dumps(self._state)
コード例 #4
0
async def agent_loop(server_address="localhost:8000",
                     agent_name="69892-73761"):
    async with websockets.connect(
            "ws://{}/player".format(server_address)) as websocket:

        # Receive information about static game properties
        await websocket.send(json.dumps({"cmd": "join", "name": agent_name}))
        msg = await websocket.recv()
        game_properties = json.loads(msg)

        mapa = Map(game_properties['map'])
        # init agent properties
        key = 'a'
        agent = Agent(None, None, None)
        pac_buf = []

        while True:
            r = await websocket.recv()
            state = json.loads(r)  # receive game state

            # Points
            energy = state['energy']
            boosts = state['boost']
            points = energy + boosts

            if not state['lives'] or points == []:
                print("GAME OVER")
                return

            # Pacman Position
            pac_pos = state['pacman']
            pac_buf.append(state['pacman'])
            agent.set_buff_pac_pos(pac_buf)
            # Ghost(s) Position(s)
            ghosts_pos = [g[0] for g in state['ghosts']]
            # Ghost(s) State
            ghosts_state = [g[1] for g in state['ghosts']]
            # Ghost(s) timeout
            ghosts_time = [g[2] for g in state['ghosts']]

            # Closest Point
            cp = agent.closest_point(pac_pos, points)

            dirs = []

            #print()
            #print('Lives: ',state['lives'])
            #print('Ghosts Pos: ',ghosts_pos)
            #print('Pacman Pos: ',pac_pos)
            #print('Cp: ',cp)

            if len(state['ghosts']) == 0:
                dirs = agent.dir_to_point(pac_pos, cp)
            elif len(state['ghosts']) >= 1:

                if len(pac_buf) == 4 and agent.check_pac_buff(pac_buf):
                    dirs = agent.dir_pac
                    pac_buf = []
                    continue
                elif len(pac_buf) > 1 and agent.check_pos_buff(pac_pos):
                    dirs = agent.dir_pac
                    continue
                elif len(pac_buf) == 4 and not agent.check_pac_buff(pac_buf):
                    pac_buf = []

                if any(ghosts_state) == True:
                    g_pos = [
                        ghosts_pos[i] for i, g in enumerate(ghosts_state)
                        if g == True
                    ]
                    for pos in g_pos:
                        dst_ghost = agent.distance_from_ghost(pac_pos, pos)
                        if dst_ghost > 1:
                            dirs = agent.dir_to_point(pac_pos, pos)
                            agent.set_dirs(dirs)
                            break
                        else:
                            dirs = agent.dir_to_point(pac_pos, cp)
                            agent.set_dirs(dirs)
                            #break
                if any(ghosts_state) == False:
                    g_pos = [
                        ghosts_pos[i] for i, g in enumerate(ghosts_state)
                        if g == False
                    ]
                    for pos in g_pos:
                        dst_ghost = agent.distance_from_ghost(pac_pos, pos)
                        if dst_ghost < 3:
                            dirs = agent.reverse_dir_to_point(pac_pos, pos)
                            if agent.distance_to_point(
                                    pac_pos, cp
                            ) > 1:  #and agent.distance_to_point(pac_pos, pos) < 5:
                                dirs = agent.dir_to_point(pac_pos, pos)
                                agent.set_dirs(dirs)
                                #dirs = agent.change_dir_escaping(pac_pos, pos, cp)
                                #print('inside if dist cp == 1: ',dirs)
                            break
                        else:
                            dirs = agent.dir_to_point(pac_pos, cp)
                            agent.set_dirs(dirs)
                            #break

            for d in dirs:
                npos = mapa.calc_pos(pac_pos, d)
                if npos != pac_pos:
                    key = d
                    break

            # send new key
            await websocket.send(json.dumps({"cmd": "key", "key": key}))