ships game

master
Vyacheslav N. Boyko 2016-12-19 00:06:27 +03:00
commit c4b53278ac
2 changed files with 454 additions and 0 deletions

1
README.md 100644
View File

@ -0,0 +1 @@
"# ships_game"

453
ships.py 100644
View File

@ -0,0 +1,453 @@
import random
from random import shuffle
from pip._vendor.distlib._backport.shutil import move
from macpath import isabs
SIZE = 10
class Utils(object) :
def _setUpCells(cells) :
global SIZE
for x in range(0, SIZE) :
for y in range(0, SIZE) :
cells.append({'x':x,'y':y})
shuffle(cells)
def _copyFieldData(field) :
data = {}
for y in field :
data[y] = {}
for x in field[y] :
data[y][x] = field[y][x]
##################################################################
class ShipsGame(object) :
""" SHIPS Game """
seed = 0
def __init__(self, seed=0) :
ShipsGame.seed = seed if seed > 0 else random.random() * 99999999
random.seed(ShipsGame.seed)
self.player = Player()
self.enemy = Player()
self.lastPlayer = None
self.winPlayer = None
self.isEnd = False
self.enemy.generateShips()
def makeMove(self, field, pos) :
ship = field.findShip(pos)
if (ship) :
ship.bomb(pos)
return True
return False
def letPlayerMove(self, pos) :
if (not self.lastPlayer or self.lastPlayer == self.enemy) :
self.makeMove(self.enemy.field, pos)
isAimedBefore = False
for aim in self.enemy.aims :
if (aim.eq(pos)) :
isAimedBefore = True
if (not isAimedBefore) :
self.enemy.aims.append(pos)
self.lastPlayer = self.player
if (self.enemy.isDead()) :
self.winPlayer = self.player
self.isEnd = True
return True
else :
return False
def letEnemyMove(self, pos) :
if (self.lastPlayer == self.player) :
self.makeMove(self.player.field, pos)
isAimedBefore = False
for aim in self.player.aims :
if (aim.eq(pos)) :
isAimedBefore = True
if (not isAimedBefore) :
self.player.aims.append(pos)
self.lastPlayer = self.enemy
if (self.player.isDead()) :
self.winPlayer = self.enemy
self.isEnd = True
return True
else :
return False
def getResult(self) :
if (self.winPlayer == self.enemy) :
return "ENEMY WIN"
elif (self.winPlayer == self.player) :
return "PLAYER WIN"
else :
return "NOT ENDED?"
class Vector2(object) :
""" X,Y Coordinates """
def __init__(self, x=0, y=0) :
self.x = x
self.y = y
self.isDead = False
def eq(self, pos) :
return self.x==pos.x and self.y==pos.y
def set(self, x, y):
self.x = x
self.y = y
def __str__(self, *args, **kwargs):
return "(x=%d,y=%d)" % (self.x, self.y)
class MoveData(object) :
def __init__(self, player, pos) :
self.player = player
self.pos = pos
class Ship(object) :
""" Ship """
def __init__(self) :
self.pos = Vector2()
self.vector = Vector2(x=1) if random.random() <= 0.5 else Vector2(y=1)
self.length = 0
self.data = []
def _create(length) :
""" Create ship by length """
s = Ship()
s.pos = Vector2()
s.vector = Vector2(x=1)
s.length = length
s.__generateData()
return s
def __generateData(self) :
""" Generates all ship's cells """
if (len(self.data) != self.length) :
self.data = []
for i in range(0, self.length) :
self.data.append(Vector2(self.pos.x + self.vector.x * i, self.pos.y + self.vector.y * i))
else :
for i in range(0, self.length) :
self.data[i].set(self.pos.x + self.vector.x * i, self.pos.y + self.vector.y * i)
def isDead(self) :
for v in self.data :
if (not v.isDead) :
return False
return True
def bomb(self, pos) :
for v in self.data :
if (v.eq(pos)) :
v.isDead = True
return True
return False
def reset(self) :
""" Resets ship position """
self.pox = Vector2()
self.vector = Vector2(x=1)
self.__generateData()
def moveTo(self, pos) :
""" Moves ship to the position """
self.pos = pos
self.__generateData()
def turn(self):
self.vector.x = 1 - self.vector.x
self.vector.y = 1 - self.vector.y
self.__generateData()
def isAt(self, pos) :
""" Check if cell belong to ship """
for v in self.data :
if (v.eq(pos)) :
return True
return False
def at(self, pos) :
for v in self.data :
if (v.eq(pos)) :
return v
return None
def asFieldPart(self) :
""" Returns all cells of ship """
field = {}
for v in self.data :
#initing all cells of ship
Field._createCell(field, v, 1)
#initing nearest cells
Field._createCell(field, Vector2(v.x-1, v.y-1), 1)
Field._createCell(field, Vector2(v.x-1, v.y), 1)
Field._createCell(field, Vector2(v.x-1, v.y+1), 1)
Field._createCell(field, Vector2(v.x, v.y-1), 1)
Field._createCell(field, Vector2(v.x, v.y+1), 1)
Field._createCell(field, Vector2(v.x+1, v.y-1), 1)
Field._createCell(field, Vector2(v.x+1, v.y), 1)
Field._createCell(field, Vector2(v.x+1, v.y+1), 1)
return field
def __str__(self, *args, **kwargs):
return "SHIP %s, len=%d, %s" % (self.pos, self.length, ("H" if self.vector.x > 0 else "V"))
class Field(object) :
"""
0 or None - empty
1 - ship
NOT >1 - ship border
2 - bombed ship
3 - failed bombing
"""
global SIZE
size = SIZE
def __init__(self, player) :
global SIZE
self.player = player
self.data = {}
self.ships = []
self.cells = []
Utils._setUpCells(self.cells)
def putShip(self, ship) :
""" Puts ship on field """
if (not Field._valid(Vector2(ship.pos.x + ship.vector.x * ship.length, ship.pos.y + ship.vector.y * ship.length))) :
return False
for v in ship.data :
if (self.__contains(v)) :
return False
shipCells = ship.asFieldPart()
for y in shipCells :
for x in shipCells[y] :
if (self.__contains(Vector2(x, y))) :
return False
for cell in ship.data :
Field._createCell(self.data, cell)
self.data[cell.y][cell.x] = 1
return True
def removeShip(self, ship) :
""" Removes ship from field """
shipCells = ship.asFieldPart()
for y in shipCells :
for x in shipCells[y] :
if (self.__contains(Vector2(x, y))) :
return False
for y in shipCells :
for x in shipCells[y] :
v = Vector2(x, y)
Field._createCell(self.data, v)
self.data[y][x] = max(0, 0 if ship.isAt(v) else (self.data[y][x] - 1))
return True
def findShip(self, pos) :
for ship in self.ships :
if (ship.isAt(pos)) :
return ship
return None
def arrangementShips(self, ships, firstShipIndex) :
""" Tries to arrangement ships recursively """
if firstShipIndex >= len(ships) :
return True
for i in range(firstShipIndex, len(ships)) :
ship = ships[i]
if (random.random() >= 0.5) :
ship.turn()
for cell in self.cells :
v = Vector2(cell['x'], cell['y'])
ship.moveTo(v)
if (self.putShip(ship)) :
if (self.arrangementShips(ships, firstShipIndex+1)) :
self.ships.append(ship)
return True
self.removeShip(ship)
if ship in self.ships :
self.ships.remove(ship)
ship.reset()
return False
def _createCell(data, pos, val=0) :
""" Creates cell into field dictionary """
if (not Field._valid(pos)) :
return
if (not pos.y in data) :
data.update({pos.y : {}})
if (not pos.x in data[pos.y]) :
data[pos.y][pos.x] = val
def _valid(pos) :
""" Checks if cell is valid into field """
return (pos.x >=0 and pos.x < Field.size and pos.y >= 0 and pos.y < Field.size)
def __contains(self, pos) :
if (pos.y in self.data and pos.x in self.data[pos.y]) :
return self.data[pos.y][pos.x] > 0
return False
def __positionIsUnderShip(self, pos) :
for ship in self.ships :
if (ship.isAt(pos)) :
return True
return False
def prepare(self) :
""" DOES NOT WORK """
raise RuntimeError("Method does not work")
for ship in self.ships :
shipCells = ship.asFieldPart()
for y in shipCells :
for x in shipCells[y] :
v = Vector2(x,y)
Field._createCell(self.data, v)
if (not ship.isAt(v)) :
self.data[y][x] = self.data[y][x]+1
def __str__(self, *args, **kwargs):
global SIZE
str = ""
for y in range(0, SIZE) :
line = "("
for x in range(0, SIZE) :
pos = Vector2(x,y)
isUnderShip = False
for ship in self.ships :
if (ship.isAt(pos)) :
line += "%s" % ('*' if ship.at(pos).isDead else '1')
isUnderShip = True
if (not isUnderShip) :
isBombed = False
for v in self.player.aims :
if (v.eq(pos)) :
line += '+'
isBombed = True
if (not isBombed) :
line += '-'
#line += "%s" % #(self.data[y][x] if (y in self.data and x in self.data[y] and self.data[y][x] > 0) else '-', )
line += ")\n"
str += line
return str
class Player(object) :
def __init__(self) :
self.field = Field(self)
self.aims = []
def isDead(self) :
for ship in self.field.ships :
if (not ship.isDead()) :
return False
return True
def generateShips(self) :
ships = []
ships.append(Ship._create(4))
for i in range(0, 2) :
ships.append(Ship._create(3))
for i in range(0, 3) :
ships.append(Ship._create(2))
for i in range(0, 4) :
ships.append(Ship._create(1))
print("Count: %s" % len(ships))
if (not self.field.arrangementShips(ships, 0)) :
raise "Could not generate ships with seed %d" % (ShipsGame.seed)
if __name__ == '__main__' :
game = ShipsGame()
game.player.generateShips()
while (not game.isEnd) :
print("\n\n")
print("ENEMY")
print(game.enemy.field)
print("PLAYER")
print(game.player.field)
command = input("ENTER MOVE: ")
pos = None
print("MOVE: %s" % command)
try :
coords = command.split(',')
x = coords[0].strip()
y = coords[1].strip()
pos = Vector2(int(x), int(y))
except :
print("WRONG COMMAND!")
continue
print("PLAYER's BOMBING: %s" % pos)
game.letPlayerMove(pos)
searching = True
cells = []
Utils._setUpCells(cells)
while (searching) :
pos = cells[int(random.random() * len(cells))]
pos = Vector2(pos['x'], pos['y'])
isAimedBefore = False
for aim in game.enemy.aims :
if (aim.eq(pos)) :
isAimedBefore = True
if (isAimedBefore) :
continue
searching = False
print("ENEMY's BOMBING: %s" % pos)
game.letEnemyMove(pos)
print("ENEMY")
print(game.enemy.field)
print("PLAYER")
print(game.player.field)
print("%s" % game.getResult())