首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python 3扫雷器

Python 3扫雷器
EN

Code Review用户
提问于 2015-12-07 15:13:02
回答 2查看 4.6K关注 0票数 4

我只想要一些关于如何改进的意见/建议。

代码语言:javascript
复制
#import 
import string
import random
import time
import pickle


#create grid
def create_grid(size,lastcell,numberofmines):
    grid = []
    for i in range(size):
        row = ['0']*size
        grid.append(row)
    mines = create_mines(grid,lastcell,numberofmines,size)
    p = surrounding(grid,size)
    p.numberofsurrounding(grid,size)
    return (grid,mines)


#show the grid 
def showgrid(grid,size):
    horizontal = ' -'+size*'----'
    collum = '   '
    #writes the collmum numbers
    for i in string.ascii_uppercase[:size]:
        collum += (i+ '   ')
    print (collum,'\n',horizontal)
    # writes row numbers
    for idx,i in enumerate(grid, start=1):
        row = str(idx)
        row += '|'
        for j in i:
            row = row+' '+j+' |'
        print (row+'\n'+horizontal)


#generated random cordinates 
def generate_cordinate(size):
    a = random.randint(0,size-1)
    b = random.randint(0,size-1)
    return (a,b)


#class fro surrounding
class surrounding(object):
    def __init__(self,grid,size):
        self.grid = grid
        self.size = size


    #creates a list with the surrounding cell for every cell
    def surrounding_cells(self,row_num,col_num,size):
        surronding = []
        for i in range(-1,2):
            for j in range(-1,2):
                if i == 0 and j == 0:
                    continue
                elif -1<row_num+i<size and -1<col_num+j<size:
                    surronding.append((row_num+i,col_num+j))
        return (surronding)


    #checks how many is mines in the surromding cells
    def numberofsurrounding(self,grid,size):
        for row_num,row in enumerate(grid):
            for col_num,col in enumerate(row):
                if col!='*':
                    #finds value of surrounding cell
                    values = [grid[r][c] for r,c in self.surrounding_cells(row_num, col_num,size)]
                    # counts how many are mines
                    grid[row_num][col_num] = str(values.count('*'))


# Generate mines
def create_mines(grid,lastcell,numberofmines,size):
    mines = []
    for i in range(numberofmines):
        cell = generate_cordinate(size)
        while cell==(lastcell[0],lastcell[1]) or cell in mines:
            cell = generate_cordinate(size)
        mines.append(cell)
    for i,j in mines: grid[i][j] = '*'
    return mines


#"shows the choose cell
def showcell(grid,showngrid,row_num,col_num,size):
    #if you pick already shown cell
    if showngrid[row_num][col_num]!='-':
        return
    #shows the cell
    showngrid[row_num][col_num] = grid[row_num][col_num]
    #if the cells value is 0 controll nearby cells
    if grid[row_num][col_num] == '0':
        p = surrounding(grid,size)
        for r,c in p.surrounding_cells(row_num,col_num,size):
            showcell(grid,showngrid,r,c,size)


# replay
def replay():
    val = input('What to go to mainmenu?(yes or no):')
    if val.lower() == 'yes':
        mainmenu('mainmenu')
    elif val.lower() == 'no':
        print('bye')
        quit()
    else:
        print('\nonly yes or no')
        replay()


#function for flags
def putflag(showngrid,row_num,col_num,flags):
    # adds flag
    if showngrid[row_num][col_num]=='-':
        showngrid[row_num][col_num] = 'F'
        flags.append((row_num,col_num))
    #remove flag
    elif showngrid[row_num][col_num]=='F':
        showngrid[row_num][col_num] = '-'
        flags.remove((row_num,col_num))


#function for picking the size/ number of mines 
def pickvalues():
    size = goodvalues(4,10,message= '\nPick size of grid(4-9):')
    numberofmines = goodvalues(size, ((size**2) -5), message= 'the number of mines has to be between ' + str(size) + ' and '+ str((size**2-6))+ '\nhow many mines::' )
    return size,numberofmines


#cheecks the values, (size/numberofmines)
def goodvalues(min,max,message):
    a = False
    while a == False:
        try:
            värde = int(input(message))
            if värde not in range(min,max):
                a = False
            if värde in range(min,max):
                a = True
        except ValueError:
            print("\nchoose an interger\n")
            a = False
    return (värde)

def name(message):
    username = input(message)
    if len(username) <= 0 or len(username) >10:
        name('Pick a username:')
    return username


#mainprogramme
def play():
    username = name('pick a username(1-10signs):')
    size,numberofmines = pickvalues()
    start_time = time.time()
    showngrid = [['-' for i in range(size)] for i in range(size)]        #skapar en kopia av spelplanen utan mines
    showgrid(showngrid,size)
    first_round = True
    flags = []
    while True:
        while True:
            flag = False
            lastcell = input('pick cell: ')
            try:
                if lastcell[2].lower() == 'f':
                    flag = True
            except IndexError:
                pass
            try:
                #Gör om kordinaterna till siffror
                lastcell = (int(lastcell[1])-1,string.ascii_lowercase.index(lastcell[0].lower()))
                break
            except (IndexError,ValueError):
                showgrid(showngrid,size)
                print ("cant choose that cell")

        #skapar spelplanen efter första rundan
        if first_round == True:
            first_round = False
            grid,mines = create_grid(size,lastcell,numberofmines)

        row_num = lastcell[0]
        col_num = lastcell[1]

        #lägger flag
        if flag == True:
            putflag(showngrid,row_num,col_num,flags)

        else:
            try:
                if grid[row_num][col_num] == '*':
                    result('Game Over',grid,showngrid,start_time,numberofmines,size,username)

                else:
                    showcell(grid,showngrid,row_num,col_num,size)
            except IndexError:
                print('\ncant choose that cell\n')

        #kcheeks for victory
        controll(grid,showngrid,size,numberofmines,start_time,username,flags,mines)

        showgrid(showngrid,size)

#kfunction to check fo victory
def controll(grid,showngrid,size,numberofmines,start_time,username,flags,mines):
    empty_cells = 0
    cellswithmines = 0
    for x in range(len(showngrid)):
        y = (showngrid[x].count('-'))
        empty_cells += y
    for x in range(len(grid)):
        z = (grid[x].count('*'))
        cellswithmines += z
    if empty_cells == cellswithmines or set(flags) == set(mines):
        result('YOU WON',grid,showngrid,start_time,numberofmines,size,username)


#shows the reuslt (lose/win)
def result(result,grid,showngrid,start_time,numberofmines,size,username):
    if result == 'Förlust':
        print('Game Over!')
        showgrid(grid,size)
        replay()
    if result == 'Vinst':
        print('*********** YOU WON! ************')
        showgrid(showngrid,size)

        score(start_time,numberofmines,size,username)


# calculates the score
def score(start_time,numberofmines,size,username):
    finish_time = time.time()
    time = start_time - finish_time
    user_score = (int((1000 * ((int(numberofmines))**2 / (int(size))) - (1.5 * time))), username)
    highscore(user_score)


#Opens highscore and adds you on the list (if youre good enough)
def highscore(user_score):
    with open ('high_scorelist.dat','rb') as file:
         high_scorelist = pickle.load(file)
    if user_score[0] > high_scorelist[len(high_scorelist)-1][0]:
        print ("YOU MADE IT!\n\n")
        high_scorelist.append(user_score)
        high_scorelist.sort(reverse=True)
        del high_scorelist[len(high_scorelist)-1]
        with open('high_scorelist.dat','wb') as file:
            pickle.dump(high_scorelist,file)
        show_highscore(high_scorelist)
        return (high_scorelist)
    else:
       show_highscore(high_scorelist)


#prints the highscore table
def show_highscore(high_scorelist):
    print('****highscore***\n\n')
    print('|        name        |    score    |')
    for i in range(10):
        print('| ',high_scorelist[i][1],' '*(17-len(high_scorelist[i][1])), end='|')
        print(high_scorelist[i][0], ' ' *(12- len(str(high_scorelist[i][0]))), end= '|\n')
    replay()


#mainmenu
def mainmenu(message):
    print(message)
    a = str(input('1. Helpmenu\n2. play\n3. Highscore\n4. quit'))
    if a == '1':
        help()
    elif a =='2':
        play()
    elif a =='3':
        highscore(user_score=(0,'test'))
    elif a == '4':
        print('Hej då!')
        quit()
    else:
        mainmenu(message='choose 1-4')


#helpmenu
def help():
    print('what can i help you with?')
    while True:
        try:
            x = int(input('1. bla\n2. blar\n3. bla\n4. play'))
            if x == 1:
                a = input(('bla '))
            elif x == 2:
                a = input(('bla'))
            elif x == 3:
                a = input('bla')
            elif x == 4:
                mainmenu(message='here we go')
        except ValueError:
            print('\nchoose\n')


#opens mainmenu
mainmenu(message='MINeSWeeper!')
EN

回答 2

Code Review用户

回答已采纳

发布于 2015-12-07 23:07:17

我试着玩你的游戏,无论是在Python 2中(经过一些修改之后),还是在Python 3中,我都无法使游戏逻辑正常工作。所以这里和那里确实有一些bug!

命名与间距

  • 在代码- This中的逗号后面和运算符周围添加空格,可以打开代码,并使理解更加清晰。
  • 对变量和函数名使用snake_case -不要在一起!通常情况下,您不会这样写,在编写代码时也不会这样做。create_grid()很好,但是showgrid()numberofsurrounding()等等.保持一致是这里的关键!
  • 在代码块周围添加垂直间距--我倾向于在forwhile循环以及if语句之后插入空行,以帮助分隔代码的逻辑部分。
  • 使用docstring来描述函数的用途--而不是在函数前面有注释,而是使用docstring,它既符合样式,又有助于现代IDE为您的函数提供一些帮助。

所以,与你的原作不同:

#创建网格def create_grid(大小、单元格、地雷数):grid = [] for i in range( size):row = “0”*size grid.append(行) mines =create_mines(网格、单元格、地雷数、大小)p=周围(网格、大小)p.numberofsurrounding(网格、大小)返回(网格、地雷)

将这四个注释应用于您的第一个函数create_grid(),结果如下:

代码语言:javascript
复制
def create_grid(size, lastcell, number_of_mines):
    """Initialize the grid with mines, and return grid and mine posistions."""

    grid = []
    for i in range(size):
        row = ['0']*size
        grid.append(row)

    mines = create_mines(grid, lastcell, number_of_mines, size)
    p = surrounding(grid, size)
    p.number_of_surrounding(grid,size)
    return (grid, mines)

改进文本处理

使用+进行大量字符串连接,这实际上不是构建字符串的好方法。您最好使用string.format,并为整个行创建模式。

下面是如何在show_grid(grid, size)中执行此操作的示例:

代码语言:javascript
复制
def show_grid(grid, size):
    """Print the full grid with headers and dividers."""

    horizontal_line = ' -{}'.format('-----'*size)    
    ROW_PATTERN = ' {:>} | {} |'

    print('     {}'.format('   '.join(string.ascii_uppercase[:size])))  
    print(horizontal_line)

    # Write rows
    for idx, gridrow in enumerate(grid, start=1):
        print(ROW_PATTERN.format(idx, ' | '.join(gridrow)))
        print(horizontal_line)

不输也不赢

在目前的代码中,没有任何获胜或松散的可能性,但这是由于在发布到code时进行编辑。但它确实说明了魔术数字或词的一个很好的观点。在您的代码中,您使用了大量的瑞典语注释,但您也使用了Förlust (即“游戏结束”或“失败”和Vinst (即:(“胜利”)作为result()中的国家指标。唯一的问题是,你用play()controll()把这些翻译成英语,但没有用result()

因此,按照现在的情况,不可能在代码中获胜或松散。通常,最好使用布尔值、TrueFalse,或者在代码顶部声明的常量。这样你就可以很容易地修改它们,如果你抓住了所有使用它的地方,就不用担心了。

通用博弈逻辑

删除一些由post造成的错误是可能的,但与一般游戏逻辑和处理相关的问题很少:

  • 你是怎么标出地雷的?-或者你的帮助区没有多大帮助。我必须在代码中阅读和搜索,以发现我可以键入a1f来标记a1单元格。
  • 你是如何中止一场游戏的?-考虑到胜利/松散没有像预期的那样起作用,我陷入了一个无法结束游戏的循环中,不得不求助于中断程序流。任何时候都可以选择辞职,那就太好了。
  • 递归的下一个游戏和游戏结束逻辑- If我赢了或者松了(在一个工作版本中),您将触发replay()函数,这个函数将依次重新开始。这个巢穴越来越深。最好在顶层有一个主循环,这样当您调用play()和游戏结束时,它会返回到这个级别,然后请求replay()
  • 使用if __name__ == '__main__':构造--很好的是,您已经创建了一个mainmenu()函数,如果这是在命名的构造中,那就更好了,因为这将允许您的脚本作为一个模块使用,也可以在命令行中运行。即do: if __name__ ==‘__main_’:mainmenu()

与高分名单

有关的一些问题

  • 如果从显示高分列表开始,它会失败--我开始测试以查看高分列表,但是它失败了,因为我还没有任何high_scorelist.dat文件.顺便说一句,这是另一个神奇的名字,它应该是顶部的常量。
  • 您可以将time隐藏在score()函数的- In my环境中,这会破坏一些内容。不能同时使用time作为导入模块和局部变量。
  • 每次添加高分时,你都会删除一个吗?-这不会让你的高分者一直空着吗?看上去有点奇怪,但我还没有测试过这部分。

总之,您的代码确实在本地工作,但是当发布时,它变得有点混乱和功能失调。您应该清理代码以避免出现神奇的单词和数字,而应该在开始时使用常量。您应该清理您的命名和间距,以使代码更容易阅读和理解。文本处理和文档化(包括代码内部和用户)也是您需要进一步研究的领域。

票数 3
EN

Code Review用户

发布于 2015-12-07 16:37:04

我不是专家,但以下是我要做的几点改进:

创建初始的“0”填充网格:

代码语言:javascript
复制
grid = [['0' for i in range(size)] for j in range(size)]

改进show_grid:

代码语言:javascript
复制
def show_grid(grid,size):
    horizontal = ' -'+size*'----'
    #writes the column numbers
    column = '   ' + '   '.join(string.ascii_uppercase[:size])
    print (column,'\n',horizontal)
    # writes row numbers
    for idx,i in enumerate(grid, start=1):
        row = str(idx)
        row += ' | ' + ' | '.join(i)
        print (row+'\n'+horizontal)

改进surrounding_cells方法:

代码语言:javascript
复制
def surrounding_cells(self,row,col,size):
    surroundings = []
    for i in range(max(row-1, 0), min(row+2, size)):
        for j in range(max(col-1, 0), min(col+2, size)):
            if i == row and j == col:
                continue
            surroundings.append((i,j))

关于goodvalues()的两个注释:不需要if värde not in range(min,max): a = False,您可以直接删除它。而且检查if min <= varde < maxif varde in range(min, max)更快(内存也更少)

管制:

代码语言:javascript
复制
def control(grid, shown_grid, size, number_of_mines, start_time, username, flags, mines):
    empty_cells = sum(row.count('-') for row in shown_grid)
    cells_with_mines = sum(row.count('*') for row in shown_grid)
    if empty_cells == cells_with_mines or set(flags) == set(mines):
        result('YOU WON', grid, shown_grid, start_time, number_of_mines, size, username)

另外,命名需要一些修正:首先,使用snake_case而不是连接Also,它将使您的代码更具可读性。此外,使用英语也是一种很好的方式(通常是这样),如果您不熟悉正确的拼写,请使用字典(或IDE内置拼写检查器)检查。最后一件事,即使出于某种原因,你使用非英语名称,至少尽量避免非ASCII符号在其中(如奥,奥等)。

我想,你可能想要创建一个游戏类,来存储诸如用户名、网格大小、地雷数量等东西。所以你可以在需要的时候取这些值,而不必每次都要传递它们。(例如,现在还不清楚结果()为什么需要这么多参数)。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/113153

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档