github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/families/battleship/sawtooth_battleship/battleship_board.py (about)

     1  # Copyright 2016 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  # ------------------------------------------------------------------------------
    15  
    16  # pylint: disable=consider-using-enumerate
    17  
    18  import logging
    19  import random
    20  import string
    21  import hashlib
    22  
    23  from sawtooth_battleship.battleship_exceptions import BoardLayoutException
    24  
    25  
    26  LOGGER = logging.getLogger(__name__)
    27  
    28  
    29  class BoardLayout(object):
    30      def __init__(self, size):
    31          self.ship_positions = []
    32          self.size = size
    33  
    34      def append(self, ship_position):
    35          """Attempts to append the ship at the specified position.
    36  
    37          Attributes:
    38              ship_position (ShipPosition): The ship to append to the layout.
    39  
    40          Raises:
    41              BoardLayoutException: If the position is already occupied or is
    42                  otherwise invalid.
    43          """
    44  
    45          self.ship_positions.append(ship_position)
    46  
    47          # Check validity by rendering the board into a string
    48          try:
    49              self.render()
    50          except BoardLayoutException as e:
    51              self.ship_positions = self.ship_positions[:-1]
    52              raise e
    53  
    54      def render(self):
    55          """Returns a game board layout as a list of strings.
    56  
    57          Raises:
    58              BoardLayoutException: If the position is already occupied or is
    59                  otherwise invalid.
    60          """
    61  
    62          board = [['-'] * self.size for i in range(self.size)]
    63  
    64          for position in self.ship_positions:
    65              orientation = position.orientation
    66              row = position.row
    67              col = position.column
    68              text = position.text
    69  
    70              if orientation == 'horizontal':
    71                  for i in range(0, len(text)):
    72                      if board[row][col + i] != '-':
    73                          raise BoardLayoutException(
    74                              "can not place ship at {}{}, space "
    75                              "is occupied with {}".format(
    76                                  'ABCDEFGHIJ'[col],
    77                                  row,
    78                                  board[row][col]))
    79                      board[row][col + i] = text[i]
    80              elif orientation == 'vertical':
    81                  for i in range(0, len(text)):
    82                      if board[row + i][col] != '-':
    83                          raise BoardLayoutException(
    84                              "can not place ship at {}{}, space "
    85                              "is occupied with {}".format(
    86                                  'ABCDEFGHIJ'[col],
    87                                  row,
    88                                  board[row][col]))
    89                      board[row + i][col] = text[i]
    90              else:
    91                  assert False, "invalid orientation: {}".format(orientation)
    92  
    93          return board
    94  
    95      def render_hashed(self, nonces):
    96          hashed_board = [[None] * self.size for _ in range(self.size)]
    97          clear_board = self.render()
    98  
    99          for row in range(0, self.size):
   100              for col in range(0, self.size):
   101                  hashed_board[row][col] = hash_space(
   102                      clear_board[row][col], nonces[row][col])
   103  
   104          return hashed_board
   105  
   106      def serialize(self):
   107          data = {}
   108          data['size'] = self.size
   109          data['positions'] = []
   110          for position in self.ship_positions:
   111              data['positions'].append(position.serialize())
   112          return data
   113  
   114      @staticmethod
   115      def deserialize(data):
   116          layout = BoardLayout(data['size'])
   117          for position in data['positions']:
   118              layout.append(ShipPosition.deserialize(position))
   119          return layout
   120  
   121      @staticmethod
   122      def generate(ships, size=10, max_placement_attempts=100):
   123  
   124          remaining = list(ships)
   125          layout = BoardLayout(size)
   126  
   127          while remaining:
   128              ship = remaining[0]
   129              remaining.remove(ship)
   130  
   131              success = False
   132              attempts = 0
   133              while not success:
   134                  attempts += 1
   135  
   136                  orientation = random.choice(
   137                      ['horizontal',
   138                       'vertical'])
   139                  if orientation == 'horizontal':
   140                      row = random.randrange(0, size)
   141                      col = random.randrange(0, size - len(ship) + 1)
   142                  else:
   143                      row = random.randrange(0, size - len(ship) + 1)
   144                      col = random.randrange(0, size)
   145  
   146                  position = ShipPosition(
   147                      text=ship, row=row, column=col, orientation=orientation)
   148  
   149                  try:
   150                      layout.append(position)
   151                      success = True
   152                  except BoardLayoutException:
   153                      if attempts > max_placement_attempts:
   154                          LOGGER.debug("exceeded attempts, resetting...")
   155                          layout = BoardLayout(size)
   156                          remaining = list(ships)
   157                          break
   158  
   159          return layout
   160  
   161  
   162  class ShipPosition(object):
   163      """Represents a ship and it's placement on the board.
   164  
   165      Attributes:
   166          text (str): Ship's textual representation (example: AAAAA, BBBB)
   167          row (int): First row on which the ship appears (starts at 0)
   168          column (int): First column on which the ship appears (starts at 0)
   169          orientation (str): Whether placed horizontal or vertical
   170      """
   171  
   172      def __init__(self, text, row, column, orientation):
   173          self.text = text
   174          self.row = row
   175          self.column = column
   176          self.orientation = orientation
   177  
   178      def serialize(self):
   179          data = {}
   180          data['text'] = self.text
   181          data['row'] = self.row
   182          data['column'] = self.column
   183          data['orientation'] = self.orientation
   184          return data
   185  
   186      @staticmethod
   187      def deserialize(data):
   188          text = data['text']
   189          row = data['row']
   190          column = data['column']
   191          orientation = data['orientation']
   192  
   193          return ShipPosition(text, row, column, orientation)
   194  
   195  
   196  def create_nonces(board_size):
   197      nonces = [[None] * board_size for _ in range(board_size)]
   198      for row in range(0, board_size):
   199          for col in range(0, board_size):
   200              nonces[row][col] = ''.join(
   201                  [random.choice(string.ascii_letters) for _ in range(0, 10)])
   202      return nonces
   203  
   204  
   205  def hash_space(space, nonce):
   206      m = hashlib.sha512()
   207      m.update(nonce.encode())
   208      m.update(space.encode())
   209      return m.hexdigest()