blob: c9bb204cd8ce2f7d932ea7f22bc96a9501991e74 [file] [log] [blame]
#// Copyright (c) 2000-2019 Ericsson Telecom AB //
#// All rights reserved. This program and the accompanying materials are made available under the terms //
#// of the Eclipse Public License v2.0 which accompanies this distribution, and is available at //
#// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
#/////////////////////////////////////////////////////////////////////////////////////////////////////////
import random, json, os, time
from Common.DsRestAPI import DsRestAPI
class BattleShip:
SOURCE_ID = 'BattleShip'
def __init__(self, directory):
self._directory = directory
# tp and state
# -1: empty -> disabled button
# 1: unknown -> buttan that can be pressed
# 2: ship on cell -> tp = 1
# 3: ship adjacent to cell
# 0: hit -> filtered invisible button
self._dsRestAPI = DsRestAPI(self._getDataHandler, self._setDataHandler)
self._userData = {}
self._createNewGame(None)
def _getDataHandler(self, request, userCredentials):
if userCredentials['username'] in self._userData:
game = self._userData[userCredentials['username']]
else:
game = self._createNewGame(userCredentials['username'])
element = request['element']
params = request['params']
if element == 'help':
with open(os.path.join(self._directory, 'help.json'), 'r') as f:
dataElements = json.load(f)
help = {'sources': [{'source': self.SOURCE_ID, 'dataElements': dataElements}]}
return {'node': {'val': json.dumps(help).encode('hex'), 'tp': 5}}
elif element == 'New':
return {'node': {'val': '0', 'tp': 1}}
elif element == 'HorizontalSize':
return {'node': {'val': str(game['horizontalSize']), 'tp': 1}}
elif element == 'VerticalSize':
return {'node': {'val': str(game['verticalSize']), 'tp': 1}}
elif element == 'Ships':
return {'node': {'val': ','.join(str(ship) for ship in game['shipSizes']), 'tp': 4}}
elif element =='Rows':
return {'list': [{'node': {'val': str(i), 'tp': 8}} for i in range(game['verticalSize'])]}
elif element == 'Columns':
return {'list': [{'node': {'val': str(i), 'tp': 8}} for i in range(game['horizontalSize'])]}
elif element == 'Guess' and len(params) == 2:
row = None
col = None
for param in params:
if param['paramName'] == 'Row':
row = int(param['paramValue'])
if param['paramName'] == 'Column':
col = int(param['paramValue'])
if row is None or col is None or row < 0 or row >= game['verticalSize'] or col < 0 or col >= game['horizontalSize'] or game['remaining'] < 0:
return {'node': {'val': '0', 'tp': -1}}
else:
return {'node': {'val': '0', 'tp': min(1, game['board'][row][col])}}
elif element == 'Status':
remaining = game['remaining']
if remaining > 0:
return {'node': {'val': '[led:blue]Missing: ' + str(remaining), 'tp': 11}}
elif remaining == 0:
return {'node': {'val': '[led:green]Victory!', 'tp': 11}}
elif remaining == -1:
return {'node': {'val': '[led:yellow]Start a new game!', 'tp': 11}}
elif remaining == -2:
return {'node': {'val': '[led:yellow]Creating game...', 'tp': 11}}
else:
return {'node': {'val': '[led:red]Error: Could not reset board. Increase board size or decrease number of ships.', 'tp': 11}}
def _setDataHandler(self, request, userCredentials):
if userCredentials['username'] is not None:
if userCredentials['username'] in self._userData:
game = self._userData[userCredentials['username']]
else:
game = self._createNewGame(userCredentials['username'])
element = request['element']
params = request['params']
content = request['content']
if element == 'New':
self._setBoard(game)
return {'node': {'val': '0', 'tp': 1}}
elif element == 'HorizontalSize':
try:
amount = int(content)
if amount > 0 and amount <= 20:
game['horizontalSize'] = amount
self._setBoard(game)
return {'node': {'val': content, 'tp': 1}}
except:
pass
return {'node': {'val': content, 'tp': -1}}
elif element == 'VerticalSize':
try:
amount = int(content)
if amount > 0 and amount <= 20:
game['verticalSize'] = amount
self._setBoard(game)
return {'node': {'val': content, 'tp': 1}}
except:
pass
return {'node': {'val': content, 'tp': -1}}
elif element == 'Ships':
try:
game['shipSizes'] = [int(ship) for ship in content.replace(' ', '').split(',')]
self._setBoard(game)
return {'node': {'val': content, 'tp': 4}}
except:
return {'node': {'val': content, 'tp': -4}}
elif element == 'Guess':
row = None
col = None
for param in params:
if param['paramName'] == 'Row':
row = int(param['paramValue'])
if param['paramName'] == 'Column':
col = int(param['paramValue'])
if row is None or col is None or row >= game['verticalSize'] or col >= game['horizontalSize']:
return {'node': {'val': '0', 'tp': -1}}
else:
if game['remaining'] > 0:
self._guess(game, row, col)
return {'node': {'val': '0', 'tp': min(1, game['board'][row][col])}}
def _createNewGame(self, username):
self._userData[username] = {
'horizontalSize': 10,
'verticalSize': 10,
'shipSizes': [6, 5, 4, 3, 3, 2, 2],
'board': [[-1]*10]*10,
'remaining': -1
}
def _guess(self, game, row, col):
if game['board'][row][col] in [1, 3]:
game['board'][row][col] = -1
elif game['board'][row][col] == 2:
game['board'][row][col] = 0
game['remaining'] -= 1
def _placeShips(self, game):
startTime = time.time()
for size in game['shipSizes']:
placed = False
while not placed:
row = random.randint(0, game['verticalSize'] - 1)
col = random.randint(0, game['horizontalSize'] - 1)
orientation = random.randint(0,4)
placed = True
i, j = row, col
for k in range(size):
if orientation == 0 and j < game['horizontalSize'] and game['board'][i][j] < 2:
j += 1
elif orientation == 1 and i < game['verticalSize'] and game['board'][i][j] < 2:
i += 1
elif orientation == 2 and j >= 0 and game['board'][i][j] < 2:
j -= 1
elif orientation == 3 and i >= 0 and game['board'][i][j] < 2:
i -= 1
else:
placed = False
break
if placed:
i, j = row, col
for k in range(size):
game['board'][i][j] = 2
for k in [-1, 0, 1]:
for l in [-1, 0, 1]:
if i+k >= 0 and i+k < game['verticalSize'] and j+l >= 0 and j+l < game['horizontalSize'] and game['board'][i+k][j+l] != 2:
game['board'][i+k][j+l] = 3
if orientation == 0:
j += 1
elif orientation == 1:
i += 1
elif orientation == 2:
j -= 1
elif orientation == 3:
i -= 1
# stop after 2 seconds of trying
if time.time() - startTime > 2:
game['remaining'] = -3
self._clearBoard()
return
def _setBoard(self, game):
board = []
for i in range(game['verticalSize']):
board.append([])
for j in range(game['horizontalSize']):
board[i].append(1)
game['board'] = board
game['remaining'] = -2
self._placeShips(game)
game['remaining'] = sum(game['shipSizes'])
def _clearBoard(self, game):
for i in range(game['verticalSize']):
game['board'].append([])
for j in range(game['horizontalSize']):
game['board'][i].append(-1)
def handleMessage(self, method, path, headers, body, userCredentials, response):
response['body'] = json.dumps(self._dsRestAPI.parseRequest(json.loads(body), userCredentials))
response['headers']['Content-Type'] = 'application/json'
def getDataSourceHandlers(self):
return {
self.SOURCE_ID: {
'getDataHandler': self._getDataHandler,
'setDataHandler': self._setDataHandler
}
}
def close(self):
pass