简单的Python战舰游戏

6
我最近开始学习Python,并决定尝试制作我的第一个项目。我正在尝试制作一款战舰游戏,随机在棋盘上放置两艘长度为3的船只。但是它并没有完全正常工作。我为第二艘船制作了一个while循环,它应该检查并查看其旁边的两个空格是否为空闲,然后在那里建造自己。但有时它会直接放在第一艘船的位置上。有人能帮帮我吗?
以下是代码的第一部分:
from random import randint

###board:

board = []

for x in range(7):
    board.append(["O"] * 7)

def print_board(board):
    for row in board:
        print " ".join(row)

###ships' positions:
#ship 1
def random_row(board):
    return randint(0, len(board) - 1)
def random_col(board):
    return randint(0, len(board[0]) - 1)
row_1 = random_row(board)
col_1 = random_col(board)

#ship 2
row_2 = random_row(board)
col_2 = random_col(board)
def make_it_different(r,c):
    while r == row_1 and c == col_1:
        r = random_row(board)
        c = random_col(board)
        row_2 = r
        col_2 = c
make_it_different(row_2,col_2)


### Makes the next two blocks of the ships:
def random_dir():
    n = randint(1,4)
    if n == 1:
        return "up"
    elif n == 2:
        return "right"
    elif n == 3:
        return "down"
    elif n == 4:
        return "left"
#ship one:
while True:
    d = random_dir() #reset direction
    if d == "up":
        if row_1 >= 2:
            #building...
            row_1_2 = row_1 - 1
            col_1_2 = col_1
            row_1_3 = row_1 - 2
            col_1_3 = col_1
            break
    if d == "right":
        if col_1 <= len(board[0])-3:
            #building...
            row_1_2 = row_1
            col_1_2 = col_1 + 1
            row_1_3 = row_1
            col_1_3 = col_1 + 2
            break
    if d == "down":
        if row_1 <= len(board)-3:
            #building...
            row_1_2 = row_1 + 1
            col_1_2 = col_1
            row_1_3 = row_1 + 2
            col_1_3 = col_1
            break
    if d == "left":
        if col_1 >= 2:
            #building...
            row_1_2 = row_1
            col_1_2 = col_1 - 1
            row_1_3 = row_1
            col_1_3 = col_1 - 2
            break
ship_1 = [(row_1,col_1),(row_1_2,col_1_2),(row_1_3,col_1_3)]

这里是“船2”部分的内容:

#ship two:
while True:
    d = random_dir() #reset direction
    if d == "up":
        if row_2 >= 2:
            if (row_2 - 1,col_2) not in ship_1 and (row_2 - 2,col_2) not in ship_1:
                #building...
                row_2_2 = row_2 - 1
                col_2_2 = col_2
                row_2_3 = row_2 - 2
                col_2_3 = col_2
                break
    if d == "right":
        if col_2 <= len(board[0])-3:
             if (row_2 ,col_2 + 1) not in ship_1 and (row_2,col_2 + 2) not in ship_1:
                #building...
                row_2_2 = row_2
                col_2_2 = col_2 + 1
                row_2_3 = row_2
                col_2_3 = col_2 + 2
                break
    if d == "down":
        if row_2 <= len(board)-3:
            if (row_2 + 1 ,col_2) not in ship_1 and (row_2 + 2,col_2) not in ship_1:
                #building...
                row_2_2 = row_2 + 1
                col_2_2 = col_2
                row_2_3 = row_2 + 2
                col_2_3 = col_2
                break
    if d == "left":
        if col_2 >= 2:
            if (row_2 ,col_2 - 1) not in ship_1 and (row_2,col_2 - 2) not in ship_1:
                #building...
                row_2_2 = row_2
                col_2_2 = col_2 - 1
                row_2_3 = row_2
                col_2_3 = col_2 - 2
                break

###test
board[row_1][col_1] = "X"
board[row_1_2][col_1_2] = "X"
board[row_1_3][col_1_3] = "X"
board[row_2][col_2] = "Y"
board[row_2_2][col_2_2] = "Y"
board[row_2_3][col_2_3] = "Y"
#Ship1 = X's and Ship2 = Y's
print_board(board)

1
看起来make_it_different函数没有做任何事情。在函数末尾加一个return,然后用这个代替:row_2, col_2 = make_it_different(row_2,col_2)。当你在函数内设置变量时,你并没有在全局范围内设置它(除非你想在函数中使用全局的row_2col_2变量,但我不建议这样做)。 - scohe001
我建议先选择船的方向,再确定其位置。 - nicolas.leblanc
快速 Python 提示:你可以使用列表推导式来创建列表,例如 board=[["O"]*WIDTH for i in range(HEIGHT)],其中我将魔法数字 7 移到变量以提高可读性。 - Blaine
3个回答

4
我建议您允许放置代码简单地运行,不要使用if语句,这样会更加简洁。然后,在结束时,您可以检查是否有任何重叠的部分,如果有,则重新设置。根据您最终决定存储个别船只所在点的方式,可能需要使用元组列表。您可以这样做:放置船只的方法可以返回一个元组列表(点)。
def placeShip():
    points = []

    # put random point generation here

    for point in points:
        if point in otherShipPoints:
            return placeShip()         # overlap detected, redo ship placement

    return points

把你的放置代码放入一个函数中,这样它可以被简单地调用。你的代码开始变得混乱,我建议采取这种方法来避免陷入意大利面条代码问题。
你还可以给placeShip()添加一个参数,表示你要添加的船的大小,然后这个方法可以成为你的全能船只放置器。只需要让你的函数看起来像这样placeShip(size),然后在你的网格内随机生成那么多个点即可。

如果在您刚完成循环时placeShip()出现错误放置,会发生什么? - scohe001
1
啊,抱歉,在你的编辑之前它看起来不像是要递归的。这样看起来更好,+1。 - scohe001
这取决于您如何实现此函数。这是伪代码,您可以随意更改它。我建议对所有船只进行操作。 - Stephan
@user2631796 如果您愿意来聊天,我可以进一步阐述。 - Stephan
请访问以下链接加入我们的聊天室:http://chat.stackoverflow.com/rooms/info/34553/mads-chat?tab=general @user2631796 - Stephan
显示剩余4条评论

2

你需要写很多代码,也许有更好的方法。试着写一个函数,例如:

def ship_points(rowcol = (3,3), shiplength = 4, direction = (1,0), boardsize=(7,7)):
    points = []
    for i in xrange(shiplength):
        points.append((rowcol[0]+i*direction[0], rowcol[1]+i*direction[1]))
        if points[i][0] >= boardsize[0] or points[i][1] >= boardsize[1]:
            return None
    return points

现在你只需为每艘船生成点并直接检查相同的点。这样代码量大大减少,而且可重用性更高。

2
make_it_different 函数中对 row_2col_2 的赋值并不会改变它们所代表的全局变量。Python 规定,函数内没有使用 global 声明的变量都是局部变量;对 row_2col_2 的赋值会创建新的局部变量而非修改全局变量。你可以通过声明 row_2col_2 为全局变量来解决这个问题,但更好的做法是将新值传递给调用者并由调用者进行赋值。
(为什么 make_it_different 要接受 row_2col_2 的初始值呢?直接生成符合条件的坐标不就好了吗?)

你在最后一部分让我有些迷惑了。你说的“生成坐标”,这不是它本来就该做的吗?如果没有这两个值,我该怎么做呢?能给我一个例子吗? - Nathan
@user2631796:实际上,它不需要采取初始值并使它们不同,如果它们不起作用的话;它只能生成值,直到它获得有效的值。 - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接