このコードは深刻な問題を抱えています。ゼロから設計を始めましょう。これは、クラスとデータ構造を設計および構築する方法の良い教訓になることを願っています。
まず、Map
クラスを中心にコードを編成する必要があります。これにより、部屋がグリッドとして表されます。「部屋 1」、「部屋 2」など (地図上で追跡するのが非常に難しい) について考えるのではなく、部屋を座標の観点から考える必要があります。
現在、プレイヤーが行ったことのある部屋しか見ていない、プレイヤーがマップの中央にとどまっている、斜めのパスなど、最初は無視している可能性のある機能がいくつかあります。それらが必要な場合は、基本的な機能が動作するようになったら、後でそれらを配置できます。今のところ、次のようなものを目指しています。
[ ]-[u] [ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
つまり、一部の部屋が接続され、他の部屋が接続されていないグリッドとして表しています。次のように、各部屋に座標ペアを持たせましょう。
0 1 2 3
0 [ ]-[u] [ ] [ ]
|
1 [ ]-[ ]-[ ] [ ]
|
2 [ ]-[ ]-[ ] [ ]
|
3 [ ]-[ ]-[ ]-[ ]
x を上に、y を横にします。左上が (0, 0)、その[u]
中にあるのが (0, 1) です。
さて、私たちのMap
クラスのコンポーネントは何でしょうか?
マップの高さ: 整数
マップの幅: 整数)
player_x, player_y: プレイヤーの座標
可能なパス: 移動できる部屋のペアのリスト。上記のマップは次のように表されます。
[((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1), (2, 1)),
((1, 0), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)), ((0, 2), (0, 3)),
((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3), (3, 3))]
大きなタプルが最初になるように各ペアを並べたことに注意してください (これは後で重要です)。
デザインができたので、そのMap
クラスを書きましょう。
必要なメソッドは、 、 、および初期化子の 4 つprint_map
ですmove
。初期化は簡単です。上記の 4 つの属性を設定するだけです。
class Map:
def __init__(self, height, width, player_x, player_y, paths):
self.height = height
self.width = width
self.x = player_x
self.y = player_y
self.paths = paths
今、move
非常に簡単です。方向 n/e/s/w を指定すると、次のようになります。
def move(self, direction):
if direction == "n":
if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
print "Cannot go north"
else:
self.y -= 1
「北」のmove
関数は、私たちがいる部屋の上に部屋への道があるかどうかをチェックするだけです。
ここで最も興味深いのは、マップの印刷です。self.height
これを行うには、行 (0 から) と列 (0 から)をループしますself.width
。(注print
:文字列の後に改行またはスペースが自動的に挿入されるため、この状況では使用できません。代わりにsys.stdout.writeを使用します。
def print_map(self):
for y in range(0, self.height):
# print the yth row of rooms
for x in range(0, self.width):
if self.x == x and self.y == y:
sys.stdout.write("[u]") # this is the player's room
else:
sys.stdout.write("[ ]") # empty room
# now see whether there's a path to the next room
if ((x, y), (x + 1, y)) in self.paths:
sys.stdout.write("-")
else:
sys.stdout.write(" ")
# now that we've written the rooms, draw paths to next row
print # newline
for x in range(0, self.width):
sys.stdout.write(" ") # spaces for above room
if ((x, y), (x, y + 1)) in self.paths:
sys.stdout.write("| ")
else:
sys.stdout.write(" ")
print
それでは、すべてをまとめて試してみましょう。コードは次のとおりです。
import sys
class Map:
def __init__(self, height, width, player_x, player_y, paths):
self.height = height
self.width = width
self.x = player_x
self.y = player_y
self.paths = paths
def move(self, direction):
if direction == "n":
if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
print "Cannot go north"
else:
self.y -= 1
if direction == "s":
if ((self.x, self.y), (self.x, self.y + 1)) not in self.paths:
print "Cannot go south"
else:
self.y += 1
if direction == "e":
if ((self.x, self.y), (self.x + 1, self.y)) not in self.paths:
print "Cannot go east"
else:
self.x += 1
if direction == "w":
if ((self.x - 1, self.y), (self.x, self.y)) not in self.paths:
print "Cannot go west"
else:
self.x -= 1
def print_map(self):
for y in range(0, self.height):
# print the yth row of rooms
for x in range(0, self.width):
if self.x == x and self.y == y:
sys.stdout.write("[u]") # this is the player's room
else:
sys.stdout.write("[ ]") # empty room
# now see whether there's a path to the next room
if ((x, y), (x + 1, y)) in self.paths:
sys.stdout.write("-")
else:
sys.stdout.write(" ")
# now that we've written the rooms, draw paths to next row
print # newline
for x in range(0, self.width):
sys.stdout.write(" ") # spaces for above room
if ((x, y), (x, y + 1)) in self.paths:
sys.stdout.write("| ")
else:
sys.stdout.write(" ")
print
paths = [((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1),
(2, 1)), ((1, 1), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)),
((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3),
(3, 3))]
m = Map(4, 4, 0, 0, paths)
while True:
m.print_map()
direction = raw_input("What direction do you want to move? [n/e/s/w] ")
m.move(direction)
マップを作成し、プレーヤーがその中を移動できるようにするセクションを下部に追加したことに注意してください。実行時の様子は次のとおりです。
Davids-MacBook-Air:test dgrtwo$ python Map.py
[u]-[ ] [ ] [ ]
|
[ ] [ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] e
[ ]-[u] [ ] [ ]
|
[ ] [ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] s
[ ]-[ ] [ ] [ ]
|
[ ] [u]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] w
Cannot go west
[ ]-[ ] [ ] [ ]
|
[ ] [u]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] e
[ ]-[ ] [ ] [ ]
|
[ ] [ ]-[u] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
このコードには多くの改善点がありますが (特に、move
メソッドが反復的です)、これは良い出発点です。地図を 20x20 にしてみると、問題なく拡大されることがわかります。
print_map
ETA: 次のように、はるかに短い形式で書き直すことができることに注意してください。
def print_map(self):
for y in range(0, self.height):
print "".join(["[%s]%s" %
("u" if self.x == x and self.y == y else " ",
"-" if ((x, y), (x + 1, y)) in self.paths else " ")
for x in range(0, self.width)])
print " " + " ".join(["|" if ((x, y), (x, y + 1)) in self.paths
else " " for x in range(0, self.width)])
しかし、これはもう少し激しいです。