Python代写:ECS32B Battleship

实现游戏Battleship,游戏本身逻辑不复杂,但是需要通过的测试集非常麻烦,特别是对于异常输入的处理。

Battleship

Goals

  • Practice using Object Oriented concepts to solve a complex problem

Problem

You are to implement the game of Battleship. If you’ve never played Battleship I suggest that you play this version.

Requirements

  • You must have at least the following classes
    • Game
    • Player
    • Board
    • Ship
  • Each class must be in its own file
  • All functions/methods must have type hints on their parameters and the return type

You are of course allowed to have more than these classes (I certainly did) but you must have the ones specified and they must be named exactly as above.

Game Configuration File

Input

The game configuration file will be passed on the command line. To be able to access it, you must use sys.argv. Please refer to this example on how to use command-line arguments.
To edit the command line argument in PyCharm click on your project and select Edit Configurations

Then fill in the parameter fields with the command line parameters. Each parameter is separated by whitespace. If one of your parameters has whitespace enclose it in quotes.

Format

The configuration file has the following format

num_rows num_cols
first_ship_name first_ship_length
second_ship_name second_ship_length
third_ship_name third_ship_name
...

All ship names will begin with a unique character and will not start with X, O, or * (the hit, miss, and blank characters). This will be important later when we are displaying the ships on the board.

As an example, the classic game of battleship has the following configuration file

10 10
Patrol 2
Submarine 3
Destroyer 3
Battleship 4
Carrier 5

These contents of these files are left up to the user but will always be correctly formated and logically consistent. For example, there will never be a configuration file where the length of the ship is larger than one of the board’s dimensions. Another legal configuration file could be

20 13
Anaconda 8
RaceCar 3
SkyScraper 12
Banana 6

Notice that

  1. The board is a different size. 20 X 13 as opposed to 10 X 10
  2. The “ships” are different
  3. There are a different number of ships. 4 instead of 5

Setting Up The Game

For each player in the game

  1. Ask the player for their name. Each player’s name must be unique. If they enter the same name as the other player they should be told this and asked for a new name. This repeats until the user finally enters a valid name.
  2. Ask them where they want to place each ship.
    • Ships should be placed in the order they are found within the configuration file.
    • First, ask the user whether they want to place the ship horizontal or vertical.
      • Any prefix of horizontal or vertical should be accepted as that word. For example, h, hori, horiz, would all mean horizontal and v, vert, verti would all mean horizontal.
    • Then ask them for coordinate they would like to place the ship in the form row, col
      • Horizontal ships are placed left to right and vertical ships are placed top to bottom.
    • If the user enters invalid input anywhere along the way they should be told what they did wrong and then you start anew at step 2.2.

Invalid Ship Placements and Response

A ship placement is invalid if

  1. An orientation that is not a prefix of either horizontal or vertical was entered.
    • {user_input} does not represent an Orientation
  2. The location is not in the form row, col
    • {user_input} is not in the form x,y
  3. Either row or col is not an integer
    • row: {row} is not a valid value for row.\n It should be an integer between 0 and {num_rows - 1}
    • col: {col} is not a valid value for column.\n It should be an integer between 0 and {num_cols - 1}
  4. The coordinate is out of bounds
    • Cannot place {ship} {direction} at {row}, {col} because it would be out of bounds.
  5. If, based on the ship’s orientation, placing the ship at that location would cause part of the ship to be placed out of bounds
    • Cannot place {ship} {direction} at {row}, {col} because it would end up out of bounds.
  6. Placing the ship at that location would cause it to overlap with another ship
    • Cannot place {ship} {direction} at {row}, {col} because it would overlap with {overlapping_ships}.
    • overlapping_ships is a list of ship initials this ship would overlap with sorted alphabetically

The Gameplay Loop

On each players turn

  1. Ask them for the location that they want to fire at in the form row, col. If they enter an invalid firing location tell them what is wrong with their input and continue to ask them for a new location they enter a valid location.
  2. Shoot that spot
    • Display Miss if they missed
    • Display You hit {player_name}’s {ship_name} if you hit a ship
    • Display You destroyed {player_name}’s {ship_name} if you destroyed it.
  3. Switch to the next player’s turn.

The game ends when all of a player’s ships have been destroyed. A ship is destroyed when all of its sections have been hit.

Invalid Firing Locations

A Firing Location is invalid if

  1. The input is not in the form row, col
    • {user_input is not a valid location.\n Enter the firing location in the form row, column
  2. Either row or col is not an integer
    • row: Row should be an integer. {row} is NOT an integer.
    • col: Column should be an integer. {col} is NOT an integer.
  3. The location is out of bounds {row}, {col} is not in bounds of our {num_rows} X {num_cols} board.
  4. The location has already been fired at
    • You have already fired at {row}, {col}.

Displaying the Board

A board should be displayed like the following example

  0 1 2 3 4 5 6 7 8 9
0 * * * * * * * * * *
1 * * * * * * * * * *
2 * * * * * * * * * *
3 * * * * * * * * * *
4 * * * * * * * * * *
5 * * * * * * * * * *
6 * * * * * * * * * *
7 * * * * * * * * * *
8 * * * * * * * * * *
9 * * * * * * * * * *

When ships are placed on the board you should use the first letter of their name to represent them. For example,

  0 1 2 3 4 5 6 7 8 9
0 * * S * * * * * * *
1 * * S * * * D * * *
2 * * S * * * D * * *
3 * * * * * * D * * *
4 * * * * * * * * C *
5 * * * * * * * * C *
6 * * * * P P * * C *
7 * * * * * * * * C *
8 * B B B B * * * C *
9 * * * * * * * * * *

Hits to a ship should be displayed as an X and misses should be displayed as a O (that’s the letter O and not zero). So after a bit of time, the player’s board might look like

  0 1 2 3 4 5 6 7 8 9
0 * * S * * * O * * *
1 * * S * * * X * * *
2 * * S * O * X * * *
3 * * * * * * D * * *
4 * * * * O * * * C *
5 * * * * * * * * C *
6 * * * * X X * * C *
7 * * * * * * O * C *
8 * B B B B * * * C *
9 * * * * * * O * * *

Examples

If you click on the test cases on Mimir you should be able to see what the output of the program looks like. Your output has to match mine so please be sure to read over some of those examples.

Hints and Suggestions

  1. Just because I said that you have to create certain classes doesn’t mean that you are limited to only having those classes. Those are only the basic classes and I did have more in my solution. When you encounter a new thing in your program don’t be afraid to make a class for it.
  2. This project is much bigger than most of you have worked on before so be prepared for a challenge. Make sure that you start early, plan out what you want to do, and ask lots of questions. It will greatly smooth out the development process for you.
  3. Be careful with references and copies and make sure you are getting the one you want. This is especially important when dealing with containers.

What to Submit

  • A zip folder that contains
    • A folder named BattleShip.
      • Which contains a python file named main.py that when run will play your game
      • And also contains the rest of your solution

Your program will be run as python3 BattleShip/main.py path_to_config_file so make sure that it can be run like this