| #// Copyright (c) 2000-2017 Ericsson Telecom AB // |
| #// All rights reserved. This program and the accompanying materials are made available under the terms // |
| #// of the Eclipse Public License v1.0 which accompanies this distribution, and is available at // |
| #// http://www.eclipse.org/legal/epl-v10.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 |