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
f4a61829
authored
Oct 21, 2020
by
source_reader
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
lab5 start
parent
5988c774
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
102 additions
and
3 deletions
README.md
comms.py
engine.py
main.py
players/player_state.py
README.md
View file @
f4a61829
...
@@ -69,3 +69,18 @@ with a USB serial connection. Code is required in the following locations:
...
@@ -69,3 +69,18 @@ with a USB serial connection. Code is required in the following locations:
|
``player_state.py``
|
``all_sunk:72``
| update logic to handle remote players |
|
``player_state.py``
|
``all_sunk:72``
| update logic to handle remote players |
|
``ship.py``
|
``to_dict:58``
| encode Ship as a dictionary |
|
``ship.py``
|
``to_dict:58``
| encode Ship as a dictionary |
|
``ship.py``
|
``from_dict:67``
| create a Ship from a dictionary |
|
``ship.py``
|
``from_dict:67``
| create a Ship from a dictionary |
Lab 5: Playing Remote Games
---------------------------
By the end of this lab you should be able to play a game of battleship against a remote opponent
over a network connection. You should also be able to detect if your opponent cheated. Code is
required in the following locations:
| File Name | Function:Line | Description |
|--------------------|------------------------------|------------------------------------------|
|
``engine.py``
|
``play:59``
| add cheat detection for player2 |
|
``player_state.py``
|
``to_dict:125``
| add hash to dict encoding |
|
``player_state.py``
|
``from_dict:155``
| set hash from dict encoding |
|
``player_state.py``
|
``is_valid:155``
| verify PlayerState |
|
``comms.py``
|
``host_tcp_server:61``
| host a battleship server |
|
``comms.py``
|
``connect_tcp_client:79``
| connect to an existing battleship server |
comms.py
View file @
f4a61829
from
typing
import
Tuple
from
typing
import
Tuple
,
BinaryIO
from
random
import
randint
from
random
import
randint
import
serial
import
serial
import
time
import
time
...
@@ -51,3 +51,38 @@ def connect_serial_client(port) -> Tuple[int, serial.Serial]:
...
@@ -51,3 +51,38 @@ def connect_serial_client(port) -> Tuple[int, serial.Serial]:
return
3
,
None
# <-- replace None with the Serial object
return
3
,
None
# <-- replace None with the Serial object
# --------- END YOUR CODE ----------
# --------- END YOUR CODE ----------
def
host_tcp_server
(
port
)
->
Tuple
[
int
,
BinaryIO
]:
"""
Host a battleship server on the specified port on all interfaces (0.0.0.0)
Uses priority 0
"""
# --------- BEGIN YOUR CODE ----------
# create Socket object
# bind to all interfaces (IP address = 0.0.0.0) on the specified port
# wait for a connection from a client
# return the connected socket
return
0
,
None
# --------- END YOUR CODE ----------
def
connect_tcp_client
(
server_address
)
->
Tuple
[
int
,
BinaryIO
]:
"""
Connect to a battleship server specified by ip_address:port
Uses priority 3
"""
# --------- BEGIN YOUR CODE ----------
# create a Socket object
# parse server_address into ip_address and port
# note the ip_address is a string and the port is an int
# connect the socket to the server
return
3
,
None
# --------- END YOUR CODE ----------
engine.py
View file @
f4a61829
...
@@ -42,10 +42,21 @@ class Engine:
...
@@ -42,10 +42,21 @@ class Engine:
# Did Player1 win?
# Did Player1 win?
if
player2_state
.
all_sunk
():
if
player2_state
.
all_sunk
():
# share all of Player1's ships with Player2 (both sunk and unsunk)
# this way if Player2 is remote, they can verify that Player1 did not cheat
player1_solved_state
=
self
.
player1
.
get_state
()
self
.
player2
.
send_state
(
player1_solved_state
,
reveal
=
True
)
# verify for ourselves that Player1 did not cheat
if
not
player1_solved_state
.
is_valid
():
print
(
"Player 1 cheated!"
)
else
:
print
(
"Player1 played a fair game"
)
return
self
.
player1
return
self
.
player1
# ==== Player2's turn ====
# ==== Player2's turn ====
# NOTE: Following the pattern above, implement cheat detection for Player2
# --------- BEGIN YOUR CODE ----------
# --------- BEGIN YOUR CODE ----------
# Following the pattern above implement the logic for Player2's turn
# Following the pattern above implement the logic for Player2's turn
...
...
main.py
View file @
f4a61829
...
@@ -49,8 +49,9 @@ def main():
...
@@ -49,8 +49,9 @@ def main():
# parse command line arguments
# parse command line arguments
parser
=
argparse
.
ArgumentParser
(
"Battleship Simulator"
)
parser
=
argparse
.
ArgumentParser
(
"Battleship Simulator"
)
parser
.
add_argument
(
"--type"
,
"-t"
,
choices
=
[
'cpu'
,
'serial-server'
,
'serial-client'
],
default
=
'cpu'
)
parser
.
add_argument
(
"--type"
,
"-t"
,
choices
=
[
'cpu'
,
'serial-server'
,
'serial-client'
,
parser
.
add_argument
(
"--interface"
,
"-i"
,
help
=
"serial device"
)
'tcp-server'
,
'tcp-client'
],
default
=
'cpu'
)
parser
.
add_argument
(
"--interface"
,
"-i"
,
help
=
"serial device, port or IP address:PORT"
)
args
=
parser
.
parse_args
()
args
=
parser
.
parse_args
()
# determine the type of opponent
# determine the type of opponent
...
@@ -62,6 +63,12 @@ def main():
...
@@ -62,6 +63,12 @@ def main():
elif
args
.
type
==
'serial-client'
:
elif
args
.
type
==
'serial-client'
:
(
priority
,
file
)
=
comms
.
connect_serial_client
(
args
.
interface
)
(
priority
,
file
)
=
comms
.
connect_serial_client
(
args
.
interface
)
them
=
players
.
Remote
(
file
,
priority
=
priority
)
them
=
players
.
Remote
(
file
,
priority
=
priority
)
elif
args
.
type
==
'tcp-server'
:
(
priority
,
file
)
=
comms
.
host_tcp_server
(
args
.
interface
)
them
=
players
.
Remote
(
file
,
priority
=
priority
)
elif
args
.
type
==
'tcp-client'
:
(
priority
,
file
)
=
comms
.
connect_tcp_client
(
args
.
interface
)
them
=
players
.
Remote
(
file
,
priority
=
priority
)
else
:
else
:
print
(
"Invalid player type"
)
print
(
"Invalid player type"
)
return
return
...
...
players/player_state.py
View file @
f4a61829
from
random
import
randint
from
random
import
randint
from
typing
import
List
,
Optional
,
Tuple
,
Dict
from
typing
import
List
,
Optional
,
Tuple
,
Dict
import
json
import
hashlib
from
ship
import
Ship
from
ship
import
Ship
from
ship
import
from_dict
as
ship_from_dict
from
ship
import
from_dict
as
ship_from_dict
...
@@ -43,6 +45,11 @@ class PlayerState:
...
@@ -43,6 +45,11 @@ class PlayerState:
pass
# <-- remove this!
pass
# <-- remove this!
# --------- END YOUR CODE ----------
# --------- END YOUR CODE ----------
# compute the hash of the ships, used for cheat detection
ship_str
=
json
.
dumps
([
ship
.
to_dict
()
for
ship
in
self
.
_ships
])
ship_bytes
=
ship_str
.
encode
(
'ascii'
)
self
.
_hash
=
hashlib
.
sha256
(
ship_bytes
)
.
hexdigest
()
"""
"""
Print the board as text, useful for debugging
Print the board as text, useful for debugging
"""
"""
...
@@ -100,6 +107,8 @@ class PlayerState:
...
@@ -100,6 +107,8 @@ class PlayerState:
# whether or not the last guess was a hit
# whether or not the last guess was a hit
self
.
_hit
=
new_state
.
_hit
self
.
_hit
=
new_state
.
_hit
# NOTE: ignore the hash, it cannot be trusted!
def
to_dict
(
self
,
reveal
=
False
)
->
Dict
:
def
to_dict
(
self
,
reveal
=
False
)
->
Dict
:
# if reveal is True, encode all ships
# if reveal is True, encode all ships
if
reveal
:
if
reveal
:
...
@@ -109,6 +118,8 @@ class PlayerState:
...
@@ -109,6 +118,8 @@ class PlayerState:
ships
=
self
.
sunk_ships
()
ships
=
self
.
sunk_ships
()
data
=
{}
data
=
{}
# NOTE: Add 'hash' to the data dictionary
# --------- BEGIN YOUR CODE ----------
# --------- BEGIN YOUR CODE ----------
# populate data with the following keys:
# populate data with the following keys:
...
@@ -120,9 +131,29 @@ class PlayerState:
...
@@ -120,9 +131,29 @@ class PlayerState:
return
data
return
data
def
is_valid
(
self
)
->
bool
:
# --------- BEGIN YOUR CODE ----------
board_matrix
:
List
[
List
[
Optional
[
Ship
]]]
=
[[
None
]
*
10
for
_
in
range
(
10
)]
# If any of the following checks fail, print a message and return False
# 1.) Make sure the ships are the right types
# 2.) Make sure ships are in valid locations
# 3.) Make sure the hits and misses are correct
# 4.) Validate board signature (make sure ships have not moved)
return
True
# --------- END YOUR CODE ----------
def
from_dict
(
data
:
Dict
)
->
PlayerState
:
def
from_dict
(
data
:
Dict
)
->
PlayerState
:
state
=
PlayerState
()
state
=
PlayerState
()
# NOTE: Set the _hash attribute based on the provided data
# --------- BEGIN YOUR CODE ----------
# --------- BEGIN YOUR CODE ----------
# set the _hit and _ships attributes based on the provided data
# set the _hit and _ships attributes based on the provided data
...
...
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