Skip to content

Instantly share code, notes, and snippets.

@dermesser
Last active May 11, 2019 08:57
Show Gist options
  • Save dermesser/966f7dbf3c658645ddb62ad7ec54d86f to your computer and use it in GitHub Desktop.
Save dermesser/966f7dbf3c658645ddb62ad7ec54d86f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 1 12:31:31 2019
@author: lbo
"""
import numpy
import random
def create_field(dim):
return numpy.zeros((dim,dim), dtype=numpy.bool)
def place_1x1_ships(field, n):
i = 0
def random_idx():
return random.randint(0, field.shape[0]-1)
while i < n:
(x, y) = (random_idx(), random_idx())
if field[x,y]:
continue
field[x,y] = True
i += 1
def read_guess(dim):
raw = input("x,y?> ")
parts = raw.split(',')
(x, y) = parts[0:2]
(x, y) = (int(x), int(y))
if x >= dim or y >= dim:
raise IndexError("Index must be in range 0..{}".format(dim-1))
return (x,y)
def loop(field, finalcount=5):
count = 0
while count < finalcount:
try:
c = read_guess(field.shape[0])
if c == None:
print("aborted")
return
(x,y) = c
if field[x,y]:
count += 1
print("BLLAAAMM")
else:
print("splash")
except KeyboardInterrupt:
return
except Exception as e:
print(e)
print("YOU WON")
if __name__ == '__main__':
f = create_field(10)
place_1x1_ships(f, 30)
loop(f)
print(f.astype(numpy.int))
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 1 12:31:31 2019
@author: lbo
"""
import numpy
import random
# Functionality for building the board.
def create_field(dim):
"""Returns a dim*dim field with int fields. 0 is empty, 1 is ship, 2 is hit ship."""
return numpy.zeros((dim,dim), dtype=numpy.int)
def place_1x1_ships(field, n):
i = 0
def random_idx():
return random.randint(0, field.shape[0]-1)
while i < n:
(x, y) = (random_idx(), random_idx())
if field[x,y] == 1:
continue
field[x,y] = 1
i += 1
def place_ship(field, size):
"""Places a `size` ship somewhere on the field.
Returns a (x, y, 'h'/'v', size) tuple indicating its position."""
direction = 'h' if random.randint(1, 100) <= 50 else 'v'
limits = (0,0)
max_idx = field.shape[0]-1
if direction == 'h': # horizontal
limits = (max_idx, max_idx-size)
else: # vertical
limits = (max_idx-size, max_idx)
while True:
(x, y) = (random.randint(0, limits[0]), random.randint(0, limits[1]))
if direction == 'h': # horizontal
if field[x,y:y+size].sum() > 0:
continue
field[x, y:y+size] = 1
# Cheat mode!
#print('size {} horiz at {},{}'.format(size, x, y))
else: # vertical
if field[x:x+size,y].sum() > 0:
continue
field[x:x+size, y] = 1
#print('size {} vert at {},{}'.format(size, x, y))
return (x, y, 'h' if direction else 'v', size)
def place_real_ships(field, spec={1: 4, 2: 3, 3: 2, 4: 1}):
"""Places ships according to `spec` (size => number) and returns a list
of (x, y, 'h'/'v', size) tuples indicating the positions."""
positions = []
for (shipsize, num) in spec.items():
for i in range(0, num):
positions.append(place_ship(field, shipsize))
return positions
# Functionality for reading guesses and checking the board.
def read_guess(dim):
"""Read a coordinate guess from the user.
Raises exceptions if invalid input is received, returns None if the user
indicated that they want to exit the game, returns (x, y) tuple of the
entered position otherwise."""
raw = input("x,y?> ")
if raw == 'ende':
return None
parts = raw.split(',')
(x, y) = parts[0:2]
(x, y) = (int(x), int(y))
if x >= dim or y >= dim:
raise IndexError("Index must be in range 0..{}".format(dim-1))
return (x,y)
def is_hit(field, c):
"""Check if there is a ship at x,y, or if there are neighbors.
Prints feedback about a hit."""
(x,y) = c
if field[x,y] == 1:
print("BLLAAAMM")
return True
elif field[x,y] == 2:
print("Don't hit them! They're already sunk!")
elif has_ship_neighbor(field, c):
print("That was close!")
else:
print("splash")
return False
def has_ship_neighbor(field, c):
count = 0
(x,y) = c
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if dx == 0 and dy == 0:
continue
if (x+dx > field.shape[0]-1 or y+dy > field.shape[1]-1 or
x+dx < 0 or y+dy < 0):
continue
count += 1 if field[x+dx, y+dy] == 1 else 0
return count > 0
def check_sunk_and_remove(field, positions):
"""Checks if any ships have sunk. Returns True if so, and removes the ship
from the positions list in-place."""
i = 0
for pos in positions:
(x, y, direction, size) = pos
# 2 indicates a hit, so if a ship consists of only 2s, it's sunk.
if (direction == 'h' and field[x,y:y+size].sum() == size*2) or (
direction == 'v' and field[x:x+size, y].sum() == size*2):
positions.pop(i)
return True
i += 1
return False
def loop(field, positions, finalcount=5):
"""Run guessing loop.
field is the playing board, positions is a list of positions as returned
by place_real_ships()."""
count = 0
while count < finalcount:
try:
c = read_guess(field.shape[0])
if c == None:
print("aborted")
return
(x,y) = c
if is_hit(field, c):
field[x,y] = 2
if check_sunk_and_remove(field, positions):
print("You sank it! Good job!")
count += 1
except KeyboardInterrupt:
return
except Exception as e:
print("oh-oh!", e)
print("YOU WON")
if __name__ == '__main__':
f = create_field(10)
positions = place_real_ships(f)
loop(f, positions)
print(f.astype(numpy.int))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment