Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
John Donnal
/
battleship
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
2313150e
authored
Sep 17, 2020
by
source_reader
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
lab3 start
parent
64f02887
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
258 additions
and
11 deletions
README.md
engine.py
main.py
players/__init__.py
players/computer.py
players/human.py
players/player.py
players/player_state.py
ship.py
utilities.py
README.md
View file @
2313150e
...
@@ -34,3 +34,20 @@ Code is required in the following locations:
...
@@ -34,3 +34,20 @@ Code is required in the following locations:
|
``utilities.py``
|
``draw_ships:18``
| draw ships on a board |
|
``utilities.py``
|
``draw_ships:18``
| draw ships on a board |
|
``player_state.py``
|
``place_ships:43``
| randomly place ships |
|
``player_state.py``
|
``place_ships:43``
| randomly place ships |
|
``sprites.py``
|
``--global--:28``
| create sprite objects |
|
``sprites.py``
|
``--global--:28``
| create sprite objects |
Lab 3: Playing the Computer
---------------------------
By the end of this lab you should be able to play a game of battleship against
your computer. Code is required in the following locations:
| File Name | Function:Line | Description |
|--------------------|-------------------|--------------------------------|
|
``human.py``
|
``get_guess:26``
| get a guess from the keyboard |
|
``computer.py``
|
``__init__:20``
| initialize _unguessed_spaces |
|
``computer.py``
|
``get_guess:34``
| make a random guess |
|
``engine.py``
|
``play:55``
| run player2's turn |
|
``utilities.py``
|
``draw_hits:26``
| add hit sprites to a board |
|
``utilities.py``
|
``draw_misses:35``
| add miss sprites to a board |
|
``player_state.py``
|
``all_sunk:72``
| determine if a player has lost |
|
``ship.py``
|
``is_hit:38``
| determine if a ship is hit |
engine.py
0 → 100644
View file @
2313150e
import
pygame
import
sys
from
pygame.locals
import
*
import
players
import
utilities
class
Engine
:
def
__init__
(
self
,
player1
:
players
.
Player
,
board1
,
player2
:
players
.
Player
,
board2
,
alert
):
self
.
player1
=
player1
self
.
board1
=
board1
self
.
player2
=
player2
self
.
board2
=
board2
self
.
alert
=
alert
def
play
(
self
)
->
players
.
Player
:
player2_hits
=
[]
player2_misses
=
[]
player1_hits
=
[]
player1_misses
=
[]
while
True
:
# ==== Player1's turn ====
guess
=
self
.
player1
.
get_guess
(
self
.
alert
)
self
.
player2
.
send_guess
(
guess
)
player2_state
=
self
.
player2
.
get_state
()
self
.
player1
.
send_state
(
player2_state
)
if
player2_state
.
is_hit
():
player2_hits
.
append
(
guess
)
else
:
player2_misses
.
append
(
guess
)
utilities
.
draw_ships
(
self
.
board2
,
player2_state
.
sunk_ships
())
utilities
.
draw_hits
(
self
.
board2
,
player2_hits
)
utilities
.
draw_misses
(
self
.
board2
,
player2_misses
)
self
.
board2
.
draw
()
pygame
.
display
.
update
()
# Did Player1 win?
if
player2_state
.
all_sunk
():
return
self
.
player1
# ==== Player2's turn ====
# --------- BEGIN YOUR CODE ----------
# Following the pattern above implement the logic for Player2's turn
# --------- END YOUR CODE ----------
# process event queue, quit if user clicks 'X' button
# if you don't do this the game will appear frozen
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
QUIT
:
pygame
.
quit
()
sys
.
exit
()
main.py
View file @
2313150e
...
@@ -2,6 +2,7 @@ import pygame
...
@@ -2,6 +2,7 @@ import pygame
from
pygame.locals
import
*
from
pygame.locals
import
*
import
sys
import
sys
import
engine
import
players
import
players
import
sprites
import
sprites
import
colors
import
colors
...
@@ -13,11 +14,12 @@ NBLOCKS = 11
...
@@ -13,11 +14,12 @@ NBLOCKS = 11
TOP_MARGIN
=
30
TOP_MARGIN
=
30
PADDING
=
10
PADDING
=
10
screen
:
pygame
.
Surface
=
pygame
.
display
.
set_mode
(((
BLOCK_SIZE
*
NBLOCKS
)
*
2
+
PADDING
*
3
,
BLOCK_SIZE
*
NBLOCKS
+
TOP_MARGIN
+
PADDING
))
def
main
():
def
main
():
pygame
.
init
()
pygame
.
init
()
screen
:
pygame
.
Surface
=
pygame
.
display
.
set_mode
(((
BLOCK_SIZE
*
NBLOCKS
)
*
2
+
PADDING
*
3
,
BLOCK_SIZE
*
NBLOCKS
+
TOP_MARGIN
+
PADDING
))
screen
.
fill
(
colors
.
screen_bkgd
)
screen
.
fill
(
colors
.
screen_bkgd
)
pygame
.
display
.
set_caption
(
'USNA Battleship'
)
pygame
.
display
.
set_caption
(
'USNA Battleship'
)
sprites
.
initialize
()
sprites
.
initialize
()
...
@@ -48,23 +50,36 @@ def main():
...
@@ -48,23 +50,36 @@ def main():
utilities
.
draw_ships
(
my_board
,
me
.
state
.
all_ships
())
utilities
.
draw_ships
(
my_board
,
me
.
state
.
all_ships
())
my_board
.
draw
()
my_board
.
draw
()
them
=
players
.
Computer
()
their_board
.
initialize
()
their_board
.
initialize
()
their_board
.
draw
()
their_board
.
draw
()
pygame
.
display
.
update
()
pygame
.
display
.
update
()
# Create an engine to run the game
game
=
engine
.
Engine
(
me
,
my_board
,
them
,
their_board
,
display_message
)
# Play battleship!
winner
=
game
.
play
()
# Display the winner in a message box
if
winner
==
me
:
display_message
(
screen
,
"You Win!"
)
elif
winner
==
them
:
display_message
(
screen
,
"You Lose!"
)
# wait until the user closes the game
# wait until the user closes the game
while
True
:
while
True
:
for
event
in
pygame
.
event
.
get
():
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
QUIT
:
if
event
.
type
==
QUIT
:
_display_message
(
screen
,
"Bye!"
)
display_message
(
"Bye!"
)
pygame
.
display
.
update
()
pygame
.
display
.
update
()
pygame
.
time
.
wait
(
1000
)
pygame
.
time
.
wait
(
1000
)
pygame
.
quit
()
pygame
.
quit
()
sys
.
exit
()
sys
.
exit
()
def
_display_message
(
screen
:
pygame
.
Surface
,
msg
:
str
):
def
display_message
(
msg
:
str
):
"""
"""
Display [msg] in the message box sprite in the center of the screen
Display [msg] in the message box sprite in the center of the screen
"""
"""
...
@@ -72,6 +87,9 @@ def _display_message(screen: pygame.Surface, msg: str):
...
@@ -72,6 +87,9 @@ def _display_message(screen: pygame.Surface, msg: str):
# make a copy of the msg_box sprite because we need to edit it
# make a copy of the msg_box sprite because we need to edit it
box
=
sprites
.
msg_box
.
copy
()
box
=
sprites
.
msg_box
.
copy
()
# save a copy of the original screen
backup
=
screen
.
copy
()
# --------- BEGIN YOUR CODE ----------
# --------- BEGIN YOUR CODE ----------
# create a text object with size 42 font of [msg]
# create a text object with size 42 font of [msg]
...
@@ -85,6 +103,13 @@ def _display_message(screen: pygame.Surface, msg: str):
...
@@ -85,6 +103,13 @@ def _display_message(screen: pygame.Surface, msg: str):
# --------- END YOUR CODE ----------
# --------- END YOUR CODE ----------
# wait 1 second
pygame
.
time
.
wait
(
1000
)
# restore the original screen
screen
.
blit
(
backup
,
(
0
,
0
))
pygame
.
display
.
update
()
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
main
()
main
()
players/__init__.py
View file @
2313150e
from
.computer
import
Computer
from
.human
import
Human
from
.human
import
Human
from
.player
import
Player
from
.player
import
Player
players/computer.py
0 → 100644
View file @
2313150e
from
random
import
randint
import
time
from
typing
import
List
,
Tuple
,
Callable
from
.player
import
Player
from
.player_state
import
PlayerState
class
Computer
(
Player
):
""" A computer player"""
def
__init__
(
self
):
self
.
priority
=
1
# list of board spaces that have not been guessed
# eg: _unguessed_spaces = [(0,0), (0,1), (0,2),...]
self
.
_unguessed_spaces
=
[]
# --------- BEGIN YOUR CODE ----------
# Populate _unguessed_spaces with every possible board space
# Hint: use two nested for loops
# --------- END YOUR CODE ----------
self
.
state
=
PlayerState
()
# the debug flag prints ship locations to the terminal
self
.
state
.
place_ships
(
debug
=
False
)
def
get_state
(
self
):
return
self
.
state
def
get_guess
(
self
,
alert
:
Callable
[[
str
],
None
])
->
Tuple
[
int
,
int
]:
# --------- BEGIN YOUR CODE ----------
# guess a random entry from _unguessed_spaces
# remove the guess from _unguessed_spaces
# enforce a short delay to make the computer
# appear to "think" about its guess
time
.
sleep
(
0.5
)
return
0
,
0
# <-- remove this!
# --------- END YOUR CODE ----------
def
send_guess
(
self
,
guess
:
Tuple
[
int
,
int
]):
self
.
state
.
add_guess
(
guess
)
players/human.py
View file @
2313150e
import
string
import
string
from
typing
import
Tuple
from
typing
import
Tuple
,
Callable
from
.player
import
Player
from
.player
import
Player
from
.player_state
import
PlayerState
from
.player_state
import
PlayerState
import
utilities
class
Human
(
Player
):
class
Human
(
Player
):
""" A human player"""
""" A human player"""
...
@@ -13,3 +13,28 @@ class Human(Player):
...
@@ -13,3 +13,28 @@ class Human(Player):
self
.
state
=
PlayerState
()
self
.
state
=
PlayerState
()
# add ships to the board randomly
# add ships to the board randomly
self
.
state
.
place_ships
()
self
.
state
.
place_ships
()
def
get_state
(
self
,
all_ships
=
False
):
return
self
.
state
def
get_guess
(
self
,
alert
:
Callable
[[
str
],
None
])
->
Tuple
[
int
,
int
]:
"""
Get a row,column guess from the user. The user should enter a lower case letter
followed by a number.
"""
# --------- BEGIN YOUR CODE ----------
# Use the get_key_input from the utilities module to read
# keyboard input, return a numeric tuple indicating the coordinates (row,col) of the user's guess
# If the user enters anything besides a-f for the row, use the alert function
# to display "bad row" and let the user make a new guess
# If the user enters anything besides 0-9 for the column, use the alert function
# to display "bad column" and let the user make a new guess (starting with the row)
return
0
,
0
# <-- remove this!
# --------- END YOUR CODE ----------
def
send_guess
(
self
,
guess
:
Tuple
[
int
,
int
]):
self
.
state
.
add_guess
(
guess
)
players/player.py
View file @
2313150e
from
typing
import
Tuple
from
typing
import
Tuple
,
Callable
from
.player_state
import
PlayerState
from
.player_state
import
PlayerState
...
@@ -9,7 +9,7 @@ class Player:
...
@@ -9,7 +9,7 @@ class Player:
def
send_state
(
self
,
state
:
PlayerState
,
reveal
=
False
):
def
send_state
(
self
,
state
:
PlayerState
,
reveal
=
False
):
pass
pass
def
get_guess
(
self
)
->
Tuple
[
int
,
int
]:
def
get_guess
(
self
,
alert
:
Callable
[[
str
],
None
]
)
->
Tuple
[
int
,
int
]:
pass
pass
def
send_guess
(
self
,
guess
:
Tuple
[
int
,
int
]):
def
send_guess
(
self
,
guess
:
Tuple
[
int
,
int
]):
...
...
players/player_state.py
View file @
2313150e
...
@@ -56,6 +56,29 @@ class PlayerState:
...
@@ -56,6 +56,29 @@ class PlayerState:
print
(
""
)
print
(
""
)
print
(
"="
*
10
)
print
(
"="
*
10
)
def
add_guess
(
self
,
guess
):
for
ship
in
self
.
_ships
:
if
ship
.
is_hit
(
guess
):
self
.
_hits
.
append
(
guess
)
self
.
_hit
=
True
return
self
.
_misses
.
append
(
guess
)
self
.
_hit
=
False
def
is_hit
(
self
)
->
bool
:
return
self
.
_hit
def
all_sunk
(
self
)
->
bool
:
# --------- BEGIN YOUR CODE ----------
# return True if all of the ships are sunk
# return False otherwise
return
False
# <-- remove this!
# --------- END YOUR CODE ----------
def
all_ships
(
self
):
def
all_ships
(
self
):
return
self
.
_ships
return
self
.
_ships
def
sunk_ships
(
self
):
return
[
ship
for
ship
in
self
.
_ships
if
ship
.
is_sunk
()]
ship.py
View file @
2313150e
class
Ship
:
class
Ship
:
def
__init__
(
self
,
length
:
int
,
row
:
int
,
def
__init__
(
self
,
length
:
int
,
row
:
int
,
...
@@ -29,4 +27,22 @@ class Ship:
...
@@ -29,4 +27,22 @@ class Ship:
self
.
col
=
col
self
.
col
=
col
self
.
is_vertical
=
is_vertical
self
.
is_vertical
=
is_vertical
# keep track of which parts of the ship are hit
self
.
_hits
=
[]
def
is_hit
(
self
,
guess
):
# ignore duplicate guesses
if
guess
in
self
.
_hits
:
return
True
# --------- BEGIN YOUR CODE ----------
# check if the guess corresponds to part of the ship
# if so add the guess to _hits and return True
# otherwise return False
return
False
# <-- remove this!
# --------- END YOUR CODE ----------
def
is_sunk
(
self
):
return
len
(
self
.
_hits
)
==
self
.
length
utilities.py
View file @
2313150e
from
typing
import
List
from
typing
import
List
,
Tuple
import
pygame
import
pygame
import
sprites
import
sprites
import
ship
import
ship
import
game_board
import
game_board
import
sys
from
pygame
import
QUIT
FONT_PATH
=
'assets/FutilePro.ttf'
FONT_PATH
=
'assets/FutilePro.ttf'
...
@@ -21,3 +24,31 @@ def draw_ships(board: game_board.GameBoard, ships: List[ship.Ship]):
...
@@ -21,3 +24,31 @@ def draw_ships(board: game_board.GameBoard, ships: List[ship.Ship]):
pass
# <-- remove this
pass
# <-- remove this
# --------- END YOUR CODE ----------
# --------- END YOUR CODE ----------
def
draw_hits
(
board
:
game_board
.
GameBoard
,
hits
:
List
[
Tuple
[
int
,
int
]]):
# --------- BEGIN YOUR CODE ----------
# add a "hit" sprite at every hit
pass
# <-- remove this
# --------- END YOUR CODE ----------
def
draw_misses
(
board
:
game_board
.
GameBoard
,
misses
:
List
[
Tuple
[
int
,
int
]]):
# --------- BEGIN YOUR CODE ----------
# add a "miss" sprite at every miss
pass
# <-- remove this
# --------- END YOUR CODE ----------
def
get_key_input
()
->
str
:
while
True
:
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
QUIT
:
pygame
.
quit
()
sys
.
exit
()
if
event
.
type
==
pygame
.
KEYDOWN
:
return
event
.
unicode
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment