java代写-Pac-Man小游戏

Programming Assignment 5 Pac-Man Part I

The goals of this assignment are:

  1. Understand Abstraction and Encapsulation (two of the four pillars) of Object-Oriented Programming;
  2. Understand how the write-up breaks up a complex problem into different simple methods to solve;
  3. Practice processing command-line arguments;
  4. Practice creating, accessing, and modifying multi-dimensional arrays;
  5. Practice designing nested-if and nested-loop logic.

Before we start:

  1. This assignment contains a 10-point quiz and a README.md description file. Failure to complete any of the sections before the deadline will lead to a 100% point deduction in the respective sections.
  2. This write-up is the main documentation of this assignment. However, you are still responsible for being aware of possible further hints/clarifications made in the lecture, discussion slides, and related pinned/emailed Piazza posts;
  3. If not specifically declared in the writeup, you cannot make any assumptions about the inputs of the method you are implementing;
  4. If certain methods returns String or char, it is important that your program returns a

    String/char formatted/shown exactly as it is in the examples.

  5. You are responsible for testing your code on your ieng6 account (which has the same java version setup as our autograder) before submission. Failure to compile will result in 0 points being awarded for the corresponding sections.

Background:

Pac-Man is a game created in May 1980 by Japanese video game designer Toru Iwatani, in which the objective is to navigate Pac-Man through a space containing dots, known as Pac-Dots, to accumulate as many points as possible by collecting the dots and eating ghosts. If you never played Pac-man before, review Wikipedia for the related material (not required). You

can even have a try by googling “Pac-Man” and the first search result would be a iframe game demo.

In this assignment, you will be creating a Java version of the Pac-Man game that can be played in the terminal (text-based). Your version of the game will only implement a subset of the original Pac-Man rule. There are also additional specification and modification made on top of the original game rule, which will be further explained below.

For Part I you will be implementing the movement logic of the game. In Part II you will build upon Part I and implementing the keyboard manipulation and save/load functionality of the game.

Setup:

Start by logging onto your ieng6 account. Then create and enter your source directory:

$ mkdir ~/PA5

$ cd ~/PA5

Download your starter files and copy them to your source directory on ieng6.

How to test your code:

To test your code, you will want to compile the file you are working on and then run it. Doing this is simple but important for you to understand.

$ cd ~/PA5

$ javac <filename>.java

You have just used the java compiler to compile your code into a class file that the Java Virtual Machine (the computer) can understand. You should now see <filename>.class in your directory. Now you need to run it.

$ java <filename>

This executes your file by entering the main method in the file. You can change the inputs to your algorithm by changing the code in the main method. Note that you don’t specify any file extensions (neither .class nor .java) when using the java command.

Also, as usual, upon submission to gradescope, your code will be tested and the results will be displayed to you. Please be aware that these test cases are basic and are not comprehensive. They do not cover any corner/edge cases. However, the test cases we grade your submissions with will test for these corner cases. It is advised that you write your own test cases to ensure that your code can handle the corner cases. It is up to you to figure out what the corner cases are.

Code Files:

GamePacman.java // The class that handles the command line arguments Board.java // The Pac-Man board you will implement PacCharacter.java // The Pac-Man character class you will implement Direction.java // Do not change

IBoard.java // Do not change

IPacCharacter.java // Do not change

README.md // Created by yourself Direction.java contains an example of good style java file.

The IBoard and IPacCharacter interface is there to make sure you implemented all the methods. You can try commenting out some of the method signatures in these 2 files to make your code compile if you want to test a particular method before implementing all of them. DO NOT forget to uncomment the method signatures before submissions.

Direction.java, IBoard.java, and IPacCharacter.java will not be graded on style.

Basic Game Operation:

Your Pac-Man is played on a simple grid of size NxN (10×10 by default). A single Pac-Man character always spawns at the center of the grid and is navigable in one of the 4 directions (UP, DOWN, LEFT, RIGHT) based on input from the user. 4 ghosts always spawn at the 4 corners of the grid and always move towards Pac-Man, chasing it. Pac-Man and the 4 ghosts move by 1 slot per valid user input. The Game is over when Pac-Man and any of the ghosts is in the same slot in the grid.

The grid is filled with Pac-dots except for the slot where Pac-Man spawned. A score is kept based on the user’s performance. The user’s score starts at zero, and is increased by a value of 10 whenever Pac-Man moves to a slot with Pac-dots in it.

Detailed description on all methods are listed below in the “Correctness” section.

Command Line Arguments:

Your Pac-Man game will have several arguments that can be passed in via the command line. GamePacman.java will process the command line arguments and then pass the proper arguments to the Board constructor (this will change in Part II) that you will be writing. In Part I, you will be able to pass in parameters to specify the size of the grid of the board.

Ex. The following way to run the program will create a new game grid with size 25×25.

$ java GamePacman -s 25

-s <integer> – used to specify the grid size

The specific flag “-s” can be used to specify the grid size you want to create. You may also choose not to use the flag and just use the default grid size. If no size is specified (or a value that is less than 3 is specified) then the default grid size of 10 should be used.

Direction Enum:

The Direction.java file (which is provided) contains the definition of the Direction enumeration type which will be used to represent the direction of a move in our Pac-Man game.

Enums are lists of constants. When you need a predefined list of values which do not represent some kind of numeric or textual data, you should use an enum. For example, we want to be able to represent 5 distinct directions (UP, DOWN, LEFT, RIGHT, STAY) that could be considered as a move in our game.

Variables of an enumerated type are known as “type-safe”. This means that an attempt to assign a value other than one of the enumerated values or null will result in a compile error. In other words, our Direction enum can only have a value of UP, DOWN, LEFT, RIGHT, or STAY.

If I wanted to create a Direction variable I could declare it by doing the following:

Direction dir;

If I then wanted to assign dir the value of UP I would do the following:

dir = Direction.UP;

All values of an enumerated type can be accessed by using the following syntax:

EnumeratedTypeName.VALUE_NAME

At some point we are going to be interested in determining what value an enumerated variable holds. To do this we can use the .equals() method that all objects have. So if I wanted to check to see if our variable dir is DOWN I could do the following:

dir.equals(Direction.DOWN)

This expression would return false since we previously set dir to hold the value UP. But if we instead did this:

dir.equals(Direction.UP)

Then the expression would return true since our variable dir indeed holds the value UP.

0

1

2

3

4

5

6

0

G

G

1

2

3

P

4

5

6

G

G

As an extra component, the Direction enum also has two data fields (X and Y) to signify a direction unit vector. The x and y components of this vector can be retrieved via the getter methods (getX() and getY()). This vector represents the direction of motion with respect to the indices of the rows and columns. This makes more sense if we take a look at a sample board with the rows and columns labeled on a 7×7 grid:

Direction (X, Y)

UP ( 0, -1)

DOWN ( 0, 1)

LEFT (-1, 0)

RIGHT ( 1, 0)

STAY ( 0, 0)

NOTE: You do not necessarily need to use the components of the Direction enums to complete the assignment. But it can help you in calculating the displacement.

Correctness (80 points):

PacCharacter.java:

In lectures, you have already learned about class and objects. This part of the assignment is meant to get you used to two of the four pillars of object-oriented design and programming: Abstraction and Encapsulation.

Abstraction, in general, is the act of representing essential features without including the background details or explanations. In object-oriented design, Abstraction is applied in the process of identifying software artifacts (objects) to model the problem domain. To simply put, abstraction is the thinking of treat everything as an object by abstracting away the features into instance variables and methods.

So let’s practice this thinking on your programming assignment! In Pac-Man game, your can treat Pac-Man and ghosts as objects. They are represented as char type in our grid, and they also have their coordinates as important properties. Thus we can abstract the characters in the Pac-Man game (in your case, Pac-Man and Ghosts,) in to a class PacCharacter with the following instance variable:

char appearance; // Representing the appearance of the character int row; // The row number of where the character is at int col; // The column number of where the character is at

After we abstract the characters into the PacCharacter class, there are a few more things we need to worry about: How do we let our game program access and modify these variables, while at the same time prevent other programs from accessing or modifying these variables against our wish? We need to hide variables in this class and set up “contracts” to only allow our own programs with the appropriate “contracts” to access.

The above process is called Encapsulation. Technically in encapsulation, the variables or data of a class is hidden from any other class and can be accessed only through member functions of the class in which they are declared.

Encapsulation can be achieved by: Declaring all the variables in the class as private and writing public methods in the class to set and get the values of variables.

Therefore, we made the above instance variables private, and set up the following getters and setters as “contracts” as following:

// Constructor

public PacCharacter(int row, int col, char appearance)

// Getter for variable row public int getRow()

// Getter for variable col public int getCol()

// Getter for variable appearance public char getAppearance()

// Setter for row and col

public void setPosition(int row, int col)

// Setter for Appearance characters

public void setAppearance(char appearance)

Constructor will take the input data and assign them to the instance variables.

Getters will return the certain instance variable. private instance variable cannot be accessed by outside class directly. A public getter is the “contract” we set for our programs to access the hidden data (private variables) inside a class.

Setters will take certain input and assign them to particular instance variables. private instance variable cannot be modified by outside class directly as well. A public setter is the “contract” we set for our programs to modify the hidden data (private variables) inside a class.

ASSUMPTIONS YOU MAY MAKE:

1. The input variables’ validities are already checked in the outside program (Your Board.java), thus you do not need to worry about invalid inputs.

You may find this part of PA intuitive and not challenging. (Think about when to use the keyword this in this class, and why?) This is just the warm up section. Buckle up. Our ride has just begun.

Board.java:

This section will dive deep into the methods you need to implement in Board.java.

Instance Variables

public final int GRID_SIZE;

// String Representation of Pac-man Game Board private char[][] grid;

// Record of where Pac-man has visited private boolean[][] visited;

// Pac-man that user controls private PacCharacter pacman;

// 4 Ghosts that controlled by the program private PacCharacter[] ghosts;

// Score Recorded for the gamer private int score;

GRID_SIZE is the side length of the grid in Pac-Man Game. The Pac-Man grid should be a square of size GRID_SIZE x GRID_SIZE.

grid is a 2D-array of type char, which represents the char representations of the slots in the Pac-Man board. The representations for different scenario is described in the following chart:

char Representation

Slot Information

‘ ‘ (Single Whitespace)

Empty Slot

‘*’ (Asterisk)

Slot which has a Pac-Dot in it

‘P’

Slot where only the Pac-Man is at

‘G’

Slot where one or more Ghosts are at (Multiple Ghosts in the same slot is still represented by one char ‘G’)

‘X’

Slot where the Pac-Man and one or more Ghosts are at (GAME OVER state, Pac-Man is consumed by one or more Ghost)

visited is a 2D-array of type boolean, which represents whether the Pac-Man has visited the slot or not. This is a simplified solution of recording Pac-Dots information in the grid, since in a

new game, slots that Pac-Man has visited will not contain Pac-Dots, and slots that Pac-Man has never visited will definitely contain Pac-Dots (because Ghosts do not consume Pac-Dots). Thus, if Pac-Man has visited a coordinate, the value of the slot at that coordinate will be true; otherwise, the value of the slot at that coordinate will be false.

Ex. The following are corresponding grid and visited, represented in a 2D format.

grid visited

G • • • •

• •

• • • •

• • • P •

• • • • •

False False False False False False True True True False False False False True False False False False True False False False False False False

If you only look at grid, you cannot know whether the slot that ghost(s) is/are located at (grid[0][0] in the above case) contain Pac-dot in it. That is one of the reasons that we need the visited boolean 2D-array.

pacman is the PacCharacter object that represents the Pac-Man.

ghosts is an array of PacCharacter objects that represents the ghosts.

score is the score recorded for the gamer. Whenever Pac-Man consumes a Pac-Dot, this score increases by 10.

Constructor:

public Board(int size);

In the constructor method, you are supposed to initialize all the instance variable above. Please note that after the constructor executed, the object array should contains initialized objects rather than null values. Failure to do so will cause the deduction of points.

When constructing pacman and ghosts, we set the following rules:

  1. For a new game, Pac-Man always spawns at the center of the grid; if GRID_SIZE is an even number, Pac-Man always spawns at the bottom-right slot of the 4 center slots;
  2. For a new game, there are always exactly 4 ghosts, which spawns at the 4 corners of the grid.

The 2D-arrays, GRID_SIZE, and score record should be initialized as the requirement in “Basic Game Operation”.

ASSUMPTIONS YOU MAY MAKE:

  1. The Pac-Man game board is always a square.
  2. There will not be more than 4 ghosts at any moment.
  3. The slot where Pac-Man spawns does not contain a Pac-Dot.
  4. You may find one or more methods below be useful in constructor.

Methods:

It is highly recommended that you implement the methods in the order it appears in the writeup.

setVisited

public void setVisited(int x, int y);

setVisited() method should set a certain slot with row number as x and col number as y to

true in the visited 2D-array.

refreshGrid

public void refreshGrid();

refreshGrid() method will update the grid 2D char array according to the information stored in visited, pacman, and ghosts, etc. After the execution of this method, grid should contains the most recent state of the Pac-Man game board. You should consider several cases such as (this list may not be comprehensive):

  1. What should be an empty slot represent?
  2. What if there is a Ghost inside slot?
  3. etc.

toString

public String toString();

toString() method returns a String representation of the object formatted as following (“_” represents whitespace, note that there are 2 spaces between elements, and “” represent newline character “\n”; the following is an initial 7×7 Board):

Score: 0

G • • • • • G

• • • • • • •

• • • • • • •

• • • P • • •

• • • • • • •

• • • • • • •

G • • • • • G

There are 2 spaces before each element in grid[][] array. The above format may not look straight on Google Docs, yet the output in terminal should looks like a square as following:

You are supposed to use StringBuilder to perform string concatenation rather than the “+” operator in this method. The reason is that StringBuilder achieves a better performance than String class when performing concatenation.

The StringBuilder class is similar to String class except that the String class is immutable, which means whenever you concatenate String objects, you are creating a new String object. StringBuilder is more flexible than String. You can add, insert, or append new contents into StringBuilder objects.

Read the java documentation linked above to find the methods you want. In this particular method, you may find append() and toString() in StringBuilder class very useful. We have started the method and included the first line (the score line) for you.

canMove

public boolean canMove(Direction direction);

canMove() method takes a Direction as parameter and returns whether the Pac-Man can move to that direction. In our implementation of the game, Pac-man cannot move across the

border of the board. You may consider our game board as being surrounded by a continuous and closed off wall.

isGameOver

public boolean isGameOver();

isGameOver() method detects whether Pac-man is in the same slot with any ghost. ASSUMPTIONS YOU MAY MAKE:

1. You do not need to update the grid board in this method. It is the job of one of other methods.

ghostMove

public Direction ghostMove(PacCharacter ghost);

Ghosts are controlled by the program, rather than the user. In our game Pac-Man, the ghosts always move towards the Pac-Man. ghostMove() method will return the Direction that the ghost will move based on the current position of pacman following the following rules:

  1. Ghost always seeks to reduce the Manhattan distance between Pac-Man and itself; if a Ghost is already at the same slot as the Pac-man is, the ghost should choose to STAY;
  2. When moving toward the Pac-Man, ghost always seeks to reduce the distance on the dimension which has the shorter distance first.
    1. Ex. If Ghost is at [0][0], and Pacman is at [3][4]. The row distance between them is 3, and the column distance between them is 4. Since the row dimension is shorter, Ghost will chose to move along the row dimension to [1][0].
  3. If the distance on both dimension is the same, ghosts always prefer to move on the column dimension first.

Please note that this is a longer and more complicated method compared to other methods in this assignment. Please read thoroughly through the 3 rules above, and group your logic based on them.

ASSUMPTIONS YOU MAY MAKE:

  1. The ghosts always use the current position of the Pac-Man, which means you should always get the coordinates of the Pac-Man from the object pacman;
  2. You do not need to update the grid board in this method. It is the job of one of other methods;
  3. You may use the Math.abs() method to help you calculate absolute value if needed;
  4. If you successfully implement this method, you will find the Pac-Man is hard to survive (, since we do not have wall inside our grid to stop the ghosts).

move

public void move(Direction direction);

move() groups the above methods together to execute a move of user after checking

canMove.

In this method, pacman should move one step to a new position; score may change depending on whether the new position contains a Pac-Dot (think what other instance variable needs to change in this scenario?); All ghosts will move one step based on the new position of the pacman.

grid need to be refreshed at the end of this method. ASSUMPTIONS YOU MAY MAKE:

  1. The precondition of this method is that canMove(Direction direction) returns

    true;

  2. All PacCharacters move 1 slot at a time;

GamePacman.java:

This section will dive deep into the methods you need to implement in game Pacman.java.

Instance Variables

// Default Size

private static final int DEFAULT_SIZE = 10;

// boardSize of the game private static int boardSize;

// The Board object user play on private static Board board;

Methods:

printUsage() method has been completed for you, please DO NOT MODIFY IT.

A sample main() method has been provided to you on how to navigate Pacman in main method. Feel free to modify it as a playground on Pac-Man.

processArgs

private static void processArgs(String[] args);

processArgs() method would take an array of String, which represents the command line arguments, and initialize the instance variable boardSize as required or print usage and exit the program. (One invalid edge case has been handled for you, you should handle the other invalid command line inputs).

In Part I, we only accept a pair of command line arguments which are: “-s <integer>”. (We will support more types of arguments in Part II!)

There are 2 ways to handle invalid inputs:

  1. Case 1: Call printUsage() and terminate the program by unsuccessful status code -1 (An example is shown in starter code);
  2. Case 2: If the input size is less than 3, modify it to the DEFAULT_SIZE, which is 10.

Input arguments requirements:

  1. Arguments must come in pairs, failure to do so will trigger Case 1 shown above;
  2. The first in the pair (in this assignment) must be “-s”, failure will trigger Case 1;
  3. If 1 and 2 are met, you may assume the second in the pair is an integer. The integer should be larger than or equal to 3, failure will trigger Case 2;
  4. If there are more than one pairs of “-s <integer>”, the last pair will overwrite the previous pair(s).

More about command line arguments:

Command line arguments are the arguments passed in when running the program. Ex. If you run the program as follows:

$ java GamePacman -s 25

String “-s” and “25” will be passed as elements in String[] args and passed into the main method as parameter:

public static void main(String[] args)

If you implement everything correctly, running the default main method with no command line argument (size is DEFAULT_SIZE) will give you the following output:

$ java GamePacman Welcome to Pac-Man! Score: 0

G • • • • • • • • G

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • P • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • • G • • • • • • • • G

Score: 10

• • • • • • • • G • G • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • P • • • •

• • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• G • • • • • • G •

Score: 20

• • • • • • • G • •

• • • • • • • • • • G • • • • • • • • •

• • • • • • • • • •

• • • • P • • • •

• • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • G • • • • G • • Score: 30

• • • • • • G • • •

• • • • • • • • • •

• • • • • • • • • • G • • • • • • • • •

• • • • • • • •

• • • • P • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • G • • G • • •

Score: 30

• • • • • G • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • • G • • • • • • •

• • • • P • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • • • • • • •

• • • • G G • • • •

Style Guide (10 points)

Make sure to read the style guidelines provided here. These guidelines for style will have to be followed for all the remaining assignments. Read them carefully. A brief summary is provided below:

  • Write a README.md file that describe what your program does.
  • Use reasonable comments to make your code clear and readable.
  • We won’t look for magic numbers
  • Use class header and method header block comments to describe the purpose of your program and methods.
  • Use reasonable variable names that are meaningful.
  • Judicious use of blank spaces around logical chunks of code makes your code much easier to read and debug.
  • Keep all lines less than 80 characters. (If the starter code exceeds 80 characters per line, you can leave it as is)

  • Use 2-4 spaces for each level of indentation. If you use emacs, it will automatically add appropriate spaces/tabs to line up indentation. If using vi or vim, use spaces to make sure each level of indentation lines up evenly.
  • Every time you open a new block of code (use a ‘{‘), indent farther. Go back to the previous level of indenting when you close the block (use a ‘}’).
  • Always recompile and run your program right before turning it in, just in case you commented out some code by mistake.

Quiz (10 points)

Complete the quiz linked here.

You can submit the quiz as many times as you want. The main goal of this quiz is to get you understand the write-up better.

Turnin Instructions

Remember the deadline to turn in your assignment is Wednesday, Feb. 6th, by 11:59 pm. You’ll be turning in your files on Gradescope.

You’ll be submitting 7 files – Board.java, GamePacman.java, PacCharacter.java, Direction.java, IBoard.java, IPacCharacter.java and README.md. You will need to create your own README.md, it is not provided to you.

Do not zip your files or submit any other files besides the files listed above. You can submit as many times as you want before the deadline. The latest submission will be considered for evaluation.