2017-11-14 4 views
1

私はタイトルを語る方法はあまりよくありませんでした。申し訳ありませんが、それは意味がない/誤解を招く。フィールドのフィールドの範囲内のチェック

注 - "ボート" は3 Oの互いに隣接配列であるので、

_|O|_ _|_|_ 
_|O|_ O|O|O 
|O| | | 

は船です。

私はランダムなスペースにn個のボートを生成するリスト(n x n)(リストを扱うリスト)を持っています。私は、ボート同士が隣り合ったり、コーナーに触れたり、お互いの上に乗ることを望んでいません。当然長いことになったように

if board[y - 2][x] == 'O' or board[y + 2][x] == 'O' ... 

とを、:

Aは、ボートは、このの静脈に別のボートの上に終わるだろうかどうかをチェックしようとしました。

私は時々フィールドにない座標をチェックしていたので、範囲外のエラーが出ました。

したがって、インデックスの範囲外に出ることなくあらゆる方向にボートをチェックできる方法はありますか?

さらに、ボートを作る方法に関するアイデアはお互いに隣り合っていないのですか?

ボートの世代のためのコードはここにある:あなたがポイントの隣人を検査するために、あまりにも退屈な繰り返しのロジックを訴えるよう

from random import * 

side = int(input()) 
game_state = [] 

def generate_initial_state(): 

    for i in range(side): 
     game_state.append([]) 
     for j in range(side): 
      game_state[i].append('.') 

    for i in range(side): 
     # Generate boat origin on random coordinates within the game board, 
     # if there's a boat already, generate new ones 
     y_cor = randint(0, side-1) 
     x_cor = randint(0, side-1) 
     while game_state[y_cor][x_cor] == 'O': 
      y_cor = randint(0, side - 1) 
      x_cor = randint(0, side - 1) 
     # Direct chooses if the boat will be generated up, down, or sideways 
     direct = randint(1, 4) 
     cycle = 0 

     while cycle < 3: 
     # Generates a boat going from origin in one direction, 
     # if the boat would end outside the board, chooses a different direction 
      if direct == 1: 
       if y_cor + 2 >= side: 
        direct = randint(1, 4) 
       else: 
        game_state[y_cor + cycle][x_cor] = 'O' 
        cycle += 1 
      elif direct == 2: 
       if x_cor + 2 >= side: 
        direct = randint(1, 4) 
       else: 
        game_state[y_cor][x_cor + cycle] = 'O' 
        cycle += 1 
      elif direct == 3: 
       if y_cor - 2 < 0: 
        direct = randint(1, 4) 
       else: 
        game_state[y_cor - cycle][x_cor] = 'O' 
        cycle += 1 
      elif direct == 4: 
       if x_cor - 2 < 0: 
        direct = randint(1, 4) 
       else: 
        game_state[y_cor][x_cor - cycle] = 'O' 
        cycle += 1 

for i in range(side): 
    print(*game_state[i]) 
+0

は「だから、私は生成されるフィールドのフィールド(n×nの)を持っているN 『で長さ3の船』あなたは正確であることができますか? 「フィールド」とは何ですか? 「ボート」とは何ですか?これを[配列]でタグ付けしましたが、実際に配列を扱っていますか? –

+0

投稿を編集しましたが、私は実際に配列を使って作業しています。何らかの理由でここに「フィールドのフィールド」と呼んでいます。また、ボートが今よりはっきりしていることを願っています。戦艦を考えて、ボードに乗せたボートを持っています。 –

+0

いいえ。あなたは、あなたが働いていることについて*具体的である必要があります。私はあなたが戦艦ゲームを作ろうとしていることを知っている、私は尋ねる、**あなたは実際にどのようなデータ構造**を持っています。 **あなたは配列で作業していますか?それは私のようには見えません。 'list'オブジェクトを使って作業しているようです。あなたは[mcve]を提供する必要があります。 –

答えて

2

最初に、2つの方向(水平と垂直)を使用するだけで、確率を変更してはいけません(モデルでは、ボートは2つの方法で生成できます)。

これは、許容インデックスを超過することによってのみインデックスのオーバーフローが発生することを許可します。これにより、傍受される可能性のあるIndexErrorが生成されます。

第2に、フラグを使用するとトリックを行うのに役立ちます。

EDIT

は、私はいくつかの他の変更を追加しました私はちょうど彼らが国境にあった場合、私のコードは、完全に有効なボートを拒否したので、ここではないバージョンがあることに気づきました。

更新:いくつかの説明

私たちはボートのランダムに選択された位置の適性を追跡するブールフラグboat_builtを使用します。すべてのテストが行​​われた後、選択が適していた場合、この変数は、決定した(True)または試験が実施されている間に障害物に遭遇した場合(False)。

boat_built &= (game_state[x_cor + k*dx][y_cor + k*dy] != "0") 

は、我々はすべてのテストのためのフラグを更新使用

boat_built場合は試験前Falseだった、それはテストの結果(False & a = False)に関係なくFalseままになります。これは意図され、それがあることを意味するので障害物はすでに遭遇しており、ボートは無効である。 boat_builtは試験前Trueた場合

一方、それはその後の試験(True & a = a)の結果が含まれています:新しいテストが失敗すると、私たちは今、障害物を発見したことを意味するので、これは、またを目的としています。

障害が早期に発生した場合でも、すべてのボートについて15回のテストがすべて実行されることに注意してください。

from random import * 

side = int(input()) 

game_state = [['.' for i in range(side)] for j in range(side)] 

l_dir = [(1, 0), (0, 1)] 

def generate_initial_state(): 

    for i in range(side): 
     boat_built = False 
     while not boat_built: 
      boat_built = True 

      y_cor = randrange(side) 
      x_cor = randrange(side) 

      dx, dy = l_dir[randrange(2)] 

      try: 
       # check that the three required cells are empty 
       for k in range(3): 
        boat_built &= (game_state[x_cor + k*dx][y_cor + k*dy] != "0") 
      except IndexError: 
       # if any is out of range, choice is invalid 
       boat_built = False 

      for k in range(5): 
       for l in [-1, 1]: 
        try: 
         # check if neighbours on the long sides are empty 
         boat_built &= (game_state[x_cor + (k-1)*dx + l*dy][y_cor + l*dx + (k-1)*dy] != "0") 
        except IndexError: 
         # if we're out of range, no obstruction 
         pass 

      for k in [-1, 3]: 
       try: 
        # check if neighbours on the short sides are empty 
        boat_built &= (game_state[x_cor + k*dx][y_cor + k*dy] != "0") 
       except IndexError: 
        # again, if we're out of range, no obstruction 
        pass 


     # if we reach this point, a valid position has been found 
     for k in range(3): 
      game_state[x_cor + k*dx][y_cor + k*dy] = "0" 


generate_initial_state() 

for i in range(side): 
    print(*game_state[i]) 
+0

ありがとう!魅力のように動作します。そして良いアドバイスも。 –

+0

boat_built&=(game_state [x_cor + k * dx] [y_cor + k * dy]!= "0")というコードで正確に何か質問してもよろしいですか?私はそれがビット演算子であることを知っています、それはそれです。 –

+0

@MarekHríbikブール値に適用すると、 "and"と同じように動作します。ここでは、 'boat_built = boat_builtと...'の代わりに)少し短くして、 'game_state [...] [...]!= 'O'' intoにすべてのテストを"累積する "単一のブール変数。ループなしで行うこともできますが、障害が発生するとすぐにループを「続行」する必要があります。 –

1

あなたのコードは、持っています。あなたはこのようなものを一つに4つのテストを回すことができる:

offset = [ 
     (0, -1), 
     (-1, 0), (1, 0), 
     (0, 1), 
    ] 
    for xoff, yoff in offset: 
     if game_state[x + xoff * cycle][y + yoff * cycle] == 'O': 
      report_collision(x, y) 

また、あなたは隣接する船を検出簡素化するために、「ボートと国境を接する」の両方の「ボート」の'O''o'を持つグリッドをマークできます。

+0

それは知っておくと便利です、チップのおかげで!私はまだ範囲エラーのインデックスを取得しているので、何か間違っている必要がありますか? –

+0

try/exceptでキャッチするか、範囲外を検出するために 'if'を使うか、空の縦の境界カラムを上下左右に空白の横線を入れて完全に消えるようにします。 –

1

あなたは以下のクラスを試してみて、それはあなたの問題を解決するかどうかを確認することができます

#! /usr/bin/env python3 
import collections 
import enum 
import random 


def main(): 
    board = Board(10, 10) 
    print(board) 
    board.place_boats([2, 3, 3, 4, 5]) 
    print('\n' + '=' * 21 + '\n') 
    print(board) 


Point = collections.namedtuple('Point', 'x, y') 
# noinspection PyArgumentList 
Orientation = enum.Enum('Orientation', 'HORIZONTAL, VERTICAL') 


class Board: 
    def __init__(self, width, height): 
     self.__width = width 
     self.__height = height 
     self.__matrix = [[False] * height for _ in range(width)] 
     self.__available = {Point(x, y) 
          for x in range(width) 
          for y in range(height)} 

    def __str__(self): 
     width = self.__width * 2 + 1 
     height = self.__height * 2 + 1 
     grid = [[' '] * width for _ in range(height)] 
     for yo, xo, character in (0, 1, '|'), (1, 0, '-'), (1, 1, '+'): 
      for y in range(yo, height, 2): 
       for x in range(xo, width, 2): 
        grid[y][x] = character 
     for x, column in enumerate(self.__matrix): 
      for y, cell in enumerate(column): 
       if cell: 
        grid[y << 1][x << 1] = '#' 
     return '\n'.join(''.join(row) for row in grid) 

    # noinspection PyAssignmentToLoopOrWithParameter 
    def place_boats(self, sizes, patience=10): 
     matrix_backup = [column.copy() for column in self.__matrix] 
     available_backup = self.__available.copy() 
     for _ in range(patience): 
      # try to place all the boats 
      for size in sizes: 
       for _ in range(patience): 
        # try to place boat of current size 
        point = random.choice(tuple(self.__available)) 
        method = random.choice(tuple(Orientation)) 
        try: 
         # try to place a boat; does not mangle the matrix 
         self.make_boat(point, size, method) 
        except RuntimeError: 
         pass 
        else: 
         # break out of inner patience loop; go to next size 
         break # on success 
       else: 
        # break to outer patience loop; start from beginning 
        self.__matrix = [column.copy() for column in matrix_backup] 
        self.__available = available_backup.copy() 
        break # on failure 
      else: 
       # break out of outer patience loop; all sizes were placed 
       break # on success 
     else: 
      raise RuntimeError('could not place the requested boats') 

    def make_boat(self, point, size, method): 
     backup = [column.copy() for column in self.__matrix] 
     unusable = set() 
     for offset in range(size): 
      if method is Orientation.HORIZONTAL: 
       block = self.mark_cell(point, x_offset=offset) 
      elif method is Orientation.VERTICAL: 
       block = self.mark_cell(point, y_offset=offset) 
      else: 
       raise ValueError('method was not understood') 
      if block: 
       unusable.update(block) 
      else: 
       self.__matrix = backup 
       raise RuntimeError('cannot place boat') 
     self.__available -= unusable 

    def mark_cell(self, point, *, x_offset=0, y_offset=0): 
     target = Point(point.x + x_offset, point.y + y_offset) 
     if target in self.__available and \ 
       0 <= target.x < self.__width and \ 
       0 <= target.y < self.__height: 
      self.__matrix[target.x][target.y] = True 
      return {Point(target.x + xo, target.y + yo) 
        for xo in range(-1, 2) 
        for yo in range(-1, 2)} 


if __name__ == '__main__': 
    main() 
関連する問題