mirror of https://github.com/bvn13/ships_game.git
commit
c4b53278ac
@ -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())
|
Loading…
Reference in new issue