代写代考 CSC148, Winter 2022

“””A1: Raccoon Raiders game objects (all tasks)

CSC148, Winter 2022

Copyright By PowCoder代写 加微信 powcoder

This code is provided solely for the personal and private use of students
taking the CSC148 course at the University of Toronto. Copying for purposes
other than this use is expressly prohibited. All forms of distribution of this
code, whether as given or with any changes, are expressly prohibited.

All of the files in this directory and all subdirectories are:
Copyright (c) 2022 , , , ,

=== Module Description ===
This module contains all of the classes necessary for a1_game.py to run.

from __future__ import annotations

from random import shuffle
from typing import List, Tuple, Optional

# Each raccoon moves every this many turns
RACCOON_TURN_FREQUENCY = 20

# Directions dx, dy
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
DIRECTIONS = [LEFT, UP, RIGHT, DOWN]

def get_shuffled_directions() -> List[Tuple[int, int]]:
Provided helper that returns a shuffled copy of DIRECTIONS.
You should use this where appropriate
to_return = DIRECTIONS[:]
shuffle(to_return)
return to_return

class GameBoard:
“””A game board on which the game is played.

=== Public Attributes ===
whether this game has ended or not
how many turns have passed in the game
the number of squares wide this board is
the number of squares high this board is

=== Representation Invariants ===
turns >= 0
height > 0
No tile in the game contains more than 1 character, except that a tile
may contain both a Raccoon and an open GarbageCan.

=== Sample Usage ===
See examples in individual method docstrings.
# === Private Attributes ===
# _player:
# the player of the game
# TODO Task #1 add any other private attribute(s) you need to keep track
# of the Characters on this board.

ended: bool
turns: int
width: int
height: int
_player: Optional[Player]

def __init__(self, w: int, h: int) -> None:
“””Initialize this Board to be of the given width and height in
squares. A board is initially empty (no characters) and no turns have
been taken.

>>> b = GameBoard(3, 3)
>>> b.width == 3
>>> b.height == 3
>>> b.turns == 0
>>> b.ended

self.ended = False
self.turns = 0

self.width = w
self.height = h

self._player = None
# TODO Task #1 initialize any other private attributes you added.

def place_character(self, c: Character) -> None:
“””Record that character is on this board.

This method should only be called from Character.__init__.

The decisions you made about new private attributes for class GameBoard
will determine what you do here.

Preconditions:
– c.board == self
– Character has not already been placed on this board.
– The tile (c.x, c.y) does not already contain a character, with the
exception being that a Raccoon can be placed on the same tile where
an unlocked GarbageCan is already present.

Note: The testing will depend on this method to set up the board,
as the Character.__init__ method calls this method.

>>> b = GameBoard(3, 2)
>>> r = Raccoon(b, 1, 1) # when a Raccoon is created, it is placed on b
>>> b.at(1, 1)[0] == r # requires GameBoard.at be implemented to work
# TODO Task #1

def at(self, x: int, y: int) -> List[Character]:
“””Return the characters at tile (x, y).

If there are no characters or if the (x, y) coordinates are not
on the board, return an empty list.
There may be as many as two characters at one tile,
since a raccoon can climb into a garbage can.

Note: The testing will depend on this method to allow us to
access the Characters on your board, since we don’t know how
you have chosen to store them in your private attributes,
so make sure it is working properly!

>>> b = GameBoard(3, 2)
>>> r = Raccoon(b, 1, 1)
>>> b.at(1, 1)[0] == r
>>> p = Player(b, 0, 1)
>>> b.at(0, 1)[0] == p
# TODO Task #1

def to_grid(self) -> List[List[chr]]:
Return the game state as a list of lists of chrs (letters) where:

‘R’ = Raccoon
‘S’ = SmartRaccoon
‘P’ = Player
‘C’ = closed GarbageCan
‘O’ = open GarbageCan
‘B’ = RecyclingBin
= Raccoon in GarbageCan
‘-‘ = Empty tile

Each inner list represents one row of the game board.

>>> b = GameBoard(3, 2)
>>> _ = Player(b, 0, 0)
>>> _ = Raccoon(b, 1, 1)
>>> _ = GarbageCan(b, 2, 1, True)
>>> b.to_grid()
[[‘P’, ‘-‘, ‘-‘], [‘-‘, ‘R’, ‘C’]]
# TODO Task #1

def __str__(self) -> str:
Return a string representation of this board.

The format is the same as expected by the setup_from_grid method.

>>> b = GameBoard(3, 2)
>>> _ = Raccoon(b, 1, 1)
>>> print(b)
>>> _ = Player(b, 0, 0)
>>> _ = GarbageCan(b, 2, 1, False)
>>> print(b)
>>> str(b)
‘P–\\n-RO’
# TODO Task #1

def setup_from_grid(self, grid: str) -> None:
Set the state of this GameBoard to correspond to the string ,
which represents a game board using the following chars:

‘R’ = Raccoon not in a GarbageCan
‘P’ = Player
‘C’ = closed GarbageCan
‘O’ = open GarbageCan
‘B’ = RecyclingBin
= Raccoon in GarbageCan
‘-‘ = Empty tile

There is a newline character between each board row.

>>> b = GameBoard(4, 4)
>>> b.setup_from_grid(‘P-B-\\n-BRB\\n–BB\\n-C–‘)
>>> str(b)
‘P-B-\\n-BRB\\n–BB\\n-C–‘
lines = grid.split(“\n”)
width = len(lines[0])
height = len(lines)
self.__init__(width, height) # reset the board to an empty board
for line in lines:
for char in line:
if char == ‘R’:
Raccoon(self, x, y)
elif char == ‘S’:
SmartRaccoon(self, x, y)
elif char == ‘P’:
Player(self, x, y)
elif char == ‘O’:
GarbageCan(self, x, y, False)
elif char == ‘C’:
GarbageCan(self, x, y, True)
elif char == ‘B’:
RecyclingBin(self, x, y)
elif char ==
GarbageCan(self, x, y, False)
Raccoon(self, x, y) # always makes it a Raccoon
# Note: the order mattered above, as we have to place the
# Raccoon BEFORE the GarbageCan (see the place_character
# method precondition)

# a helper method you may find useful in places
def on_board(self, x: int, y: int) -> bool:
“””Return True iff the position x, y is within the boundaries of this
board (based on its width and height), and False otherwise.
return 0 <= x <= self.width - 1 and 0 <= y <= self.height - 1 def give_turns(self) -> None:
“””Give every turn-taking character one turn in the game.

The Player should take their turn first and the number of turns
should be incremented by one. Then each other TurnTaker
should be given a turn if RACCOON_TURN_FREQUENCY turns have occurred
since the last time the TurnTakers were given their turn.

After all turns are taken, check_game_end should be called to
determine if the game is over.

Precondition:
self._player is not None

>>> b = GameBoard(4, 3)
>>> p = Player(b, 0, 0)
>>> r = Raccoon(b, 1, 1)
>>> b.turns
>>> for _ in range(RACCOON_TURN_FREQUENCY – 1):
… b.give_turns()
>>> b.turns == RACCOON_TURN_FREQUENCY – 1
>>> (r.x, r.y) == (1, 1) # Raccoon hasn’t had a turn yet
>>> (p.x, p.y) == (0, 0) # Player hasn’t had any inputs
>>> p.record_event(RIGHT)
>>> b.give_turns()
>>> (r.x, r.y) != (1, 1) # Raccoon has had a turn!
>>> (p.x, p.y) == (1, 0) # Player moved right!
# TODO Task #2 make the player take a turn by adding
# a line of code here
self.turns += 1 # PROVIDED, DO NOT CHANGE

if self.turns % RACCOON_TURN_FREQUENCY == 0: # PROVIDED, DO NOT CHANGE
pass # TODO Task #4 replace pass with code here to make each
# raccoon take a turn

self.check_game_end() # PROVIDED, DO NOT CHANGE

def handle_event(self, event: Tuple[int, int]) -> None:
“””Handle a user-input event.

The board’s Player records the event that happened, so that when the
Player gets a turn, it can make the move that the user input indicated.
self._player.record_event(event)

def check_game_end(self) -> Optional[int]:
“””Check if this game has ended. A game ends when all the raccoons on
this game board are either inside a can or trapped.

If the game has ended:
– update the ended attribute to be True
– Return the score, where the score is given by:
(number of raccoons trapped) * 10 + the adjacent_bin_score
If the game has not ended:
– update the ended attribute to be False
– return None

>>> b = GameBoard(3, 2)
>>> _ = Raccoon(b, 1, 0)
>>> _ = Player(b, 0, 0)
>>> _ = RecyclingBin(b, 1, 1)
>>> b.check_game_end() is None
>>> b.ended
>>> _ = RecyclingBin(b, 2, 0)
>>> b.check_game_end()
>>> b.ended
# TODO Task #3 (you can leave calculating the score until Task #5)

def adjacent_bin_score(self) -> int:
Return the size of the largest cluster of adjacent recycling bins
on this board.

Two recycling bins are adjacent when they are directly beside each other
in one of the four directions (up, down, left, right).

See Task #5 in the handout for ideas if you aren’t sure how
to approach this problem.

>>> b = GameBoard(3, 3)
>>> _ = RecyclingBin(b, 1, 1)
>>> _ = RecyclingBin(b, 0, 0)
>>> _ = RecyclingBin(b, 2, 2)
>>> print(b)
>>> b.adjacent_bin_score()
>>> _ = RecyclingBin(b, 2, 1)
>>> print(b)
>>> b.adjacent_bin_score()
>>> _ = RecyclingBin(b, 0, 1)
>>> print(b)
>>> b.adjacent_bin_score()
# TODO Task #5

class Character:
“””A character that has (x,y) coordinates and is associated with a given

This class is abstract and should not be directly instantiated.

NOTE: To reduce the amount of documentation in subclasses, we have chosen
not to repeat information about the public attributes in each subclass.
Remember that the attributes are not inherited, but only exist once we call
the __init__ of the parent class.

=== Public Attributes ===
the game board that this Character is on
the coordinates of this Character on the board

=== Representation Invariants ===
x, y are valid coordinates in board (i.e. board.on_board(x, y) is True)
board: GameBoard

def __init__(self, b: GameBoard, x: int, y: int) -> None:
“””Initialize this Character with board , and
at tile (, ).

When a Character is initialized, it is placed on board
by calling the board’s place_character method. Refer to the
preconditions of place_character, which must be satisfied.
self.board = b
self.x, self.y = x, y
self.board.place_character(self) # this associates self with the board!

def move(self, direction: Tuple[int, int]) -> bool:
Move this character to the tile

(self.x + direction[0], self.y + direction[1]) if possible. Each child
class defines its own version of what is possible.

Return True if the move was successful and False otherwise.

raise NotImplementedError

def get_char(self) -> chr:
Return a single character (letter) representing this Character.
raise NotImplementedError

# Note: You can safely ignore PyCharm’s warning about this class
# not implementing abstract method(s) from its parent class.
class TurnTaker(Character):
A Character that can take a turn in the game.

This class is abstract and should not be directly instantiated.

def take_turn(self) -> None:
Take a turn in the game. This method must be implemented in any subclass
raise NotImplementedError

class RecyclingBin(Character):
“””A recycling bin in the game.

=== Sample Usage ===
>>> rb = RecyclingBin(GameBoard(4, 4), 2, 1)
>>> rb.x, rb.y

def move(self, direction: Tuple[int, int]) -> bool:
“””Move this recycling bin to tile:
(self.x + direction[0], self.y + direction[1])
if possible and return whether or not this move was successful.

If the new tile is occupied by another RecyclingBin, push
that RecyclingBin one tile away in the same direction and take
its tile (as described in the Assignment 1 handout).

If the new tile is occupied by any other Character or if it
is beyond the boundaries of the board, do nothing and return False.

Precondition:
direction in DIRECTIONS

>>> b = GameBoard(4, 2)
>>> rb = RecyclingBin(b, 0, 0)
>>> rb.move(UP)
>>> rb.move(DOWN)
>>> b.at(0, 1) == [rb]
# TODO Task #2

def get_char(self) -> chr:
Return the character ‘B’ representing a RecyclingBin.
return ‘B’

class Player(TurnTaker):
“””The Player of this game.

=== Sample Usage ===
>>> b = GameBoard(3, 1)
>>> p = Player(b, 0, 0)
>>> p.record_event(RIGHT)
>>> p.take_turn()
>>> (p.x, p.y) == (1, 0)
>>> g = GarbageCan(b, 0, 0, False)
>>> p.move(LEFT)
>>> g.locked
# === Private Attributes ===
# _last_event:
# The direction corresponding to the last keypress event that the user
# made, or None if there is currently no keypress event left to process
_last_event: Optional[Tuple[int, int]]

def __init__(self, b: GameBoard, x: int, y: int) -> None:
“””Initialize this Player with board ,
and at tile (, ).”””

TurnTaker.__init__(self, b, x, y)
self._last_event = None

def record_event(self, direction: Tuple[int, int]) -> None:
“””Record that is the last direction that the user
has specified for this Player to move. Next time take_turn is called,
this direction will be used.
Precondition:
direction is in DIRECTIONS
self._last_event = direction

def take_turn(self) -> None:
“””Take a turn in the game.

For a Player, this means responding to the last user input recorded
by a call to record_event.
if self._last_event is not None:
self.move(self._last_event)
self._last_event = None

def move(self, direction: Tuple[int, int]) -> bool:
“””Attempt to move this Player to the tile:
(self.x + direction[0], self.y + direction[1])
if possible and return True if the move is successful.

If the new tile is occupied by a Racooon, a locked GarbageCan, or if it
is beyond the boundaries of the board, do nothing and return False.

If the new tile is occupied by a movable RecyclingBin, the player moves
the RecyclingBin and moves to the new tile.

If the new tile is unoccupied, the player moves to that tile.

If a Player attempts to move towards an empty, unlocked GarbageCan, the
GarbageCan becomes locked. The player’s position remains unchanged in
this case. Also return True in this case, as the Player has performed
the action of locking the GarbageCan.

Precondition:
direction in DIRECTIONS

>>> b = GameBoard(4, 2)
>>> p = Player(b, 0, 0)
>>> p.move(UP)
>>> p.move(DOWN)
>>> b.at(0, 1) == [p]
>>> _ = RecyclingBin(b, 1, 1)
>>> p.move(RIGHT)
>>> b.at(1, 1) == [p]
# TODO Task #2

def get_char(self) -> chr:
Return the character ‘P’ representing this Player.
return ‘P’

class Raccoon(TurnTaker):
“””A raccoon in the game.

=== Public Attributes ===
inside_can:
whether or not this Raccoon is inside a garbage can

=== Representation Invariants ===
inside_can is True iff this Raccoon is on the same tile as an open
GarbageCan.

=== Sample Usage ===
>>> r = Raccoon(GameBoard(11, 11), 5, 10)
>>> r.x, r.y
>>> r.inside_can
inside_can: bool

def __init__(self, b: GameBoard, x: int, y: int) -> None:
“””Initialize this Raccoon with board , and
at tile (, ). Initially a Raccoon is not inside
of a GarbageCan, unless it is placed directly inside an open GarbageCan.

>>> r = Raccoon(GameBoard(5, 5), 5, 10)
self.inside_can = False
# since this raccoon may be placed inside an open garbage can,
# we need to initially set the inside_can attribute
# BEFORE calling the parent init, which is where the raccoon is actually
# placed on the board.
TurnTaker.__init__(self, b, x, y)

def check_trapped(self) -> bool:
“””Return True iff this raccoon is trapped. A trapped raccoon is
surrounded on 4 sides (diagonals don’t matter) by recycling bins, other
raccoons (including ones in garbage cans), the player, and/or board
edges. Essentially, a raccoon is trapped when it has nowhere it could

Reminder: A racooon cannot move diagonally.

>>> b = GameBoard(3, 3)
>>> r = Raccoon(b, 2, 1)
>>> _ = Raccoon(b, 2, 2)
>>> _ = Player(b, 2, 0)
>>> r.check_trapped()
>>> _ = RecyclingBin(b, 1, 1)
>>> r.check_trapped()
# TODO Task #3

def move(self, direction: Tuple[int, int]) -> bool:
“””Attempt to move this Raccoon in and return whether
or not this was successful.

If the tile one tile over in that direction is occupied by the Player,
a RecyclingBin, or another Raccoon, OR if the tile is not within the
boundaries of the board, do nothing and return False.

If the tile is occupied by

程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com