首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >游戏玩偶游戏

游戏玩偶游戏
EN

Code Review用户
提问于 2016-10-03 15:28:25
回答 1查看 488关注 0票数 3

我成功地完成了这场比赛,我相信你以前也遇到过。如果你运行它,就会有关于该做什么的说明。有什么代码建议/改进吗?

代码语言:javascript
复制
import pygame,random,math
from time import sleep

pygame.init()

#window resolution
screen_width = 800
screen_height = 800

screen = pygame.display.set_mode( ( screen_width,screen_height ) )
pygame.display.set_caption( 'The Flash Game - Marek Borik' )

n_squares_in_row = 7
line_thickness = 20 #pixels

wait_duration = 1.5 #seconds
flash_duration = 0.3 #seconds

fontsize = screen_width // 25
rounds = 10 #rounds of flashes

#defining colors
RED = ( 255,0,0 )
BLUE = ( 0,0,255 )
WHITE = ( 255,255,255 )
BLACK = ( 0,0,0 )


def TextObjects( string,font,color ):
    textSurface = font.render( string,True,color )
    return textSurface,textSurface.get_rect()


def DrawText( string,fontSizeX,color,x,y ):
    text = pygame.font.SysFont( "timesnewroman",int( math.ceil( fontSizeX ) ) )
    TextSurf, TextRect = TextObjects( string,text,color )
    TextRect.center = ( x,y )
    screen.blit( TextSurf,TextRect )


def GenerateColorInfo( n_squares_in_row ):
    n_squares_total = n_squares_in_row ** 2

    not5050 = True #Prevents from having the same amount of red and blue squares if applicable ( e.g. field with dimentions 7 x 7 squares squares will never have this issue )

    while( not5050 ):
        color_info = []

        for i in range( n_squares_total + 1 ):
            rand = random.randint( 0,1 )
            color_info.append( rand )

        counter_red = 0
        counter_blue = 0

        for i in color_info:
            if i == 0:
                counter_red += 1
            if i == 1:
                counter_blue += 1

        if counter_red == n_squares_total // 2 or counter_blue == n_squares_total // 2 or counter_red == counter_blue:
            not5050 = True
        else:
            not5050 = False


    return color_info,counter_red,counter_blue


def DrawSquares( n_squares_in_row,color_info,square_width,square_height ):
    for i in range( n_squares_in_row ):
        for j in range( n_squares_in_row ):
            if color_info[ i * n_squares_in_row + j ] == 0:
                pygame.draw.rect( screen,RED,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )
            else:
                pygame.draw.rect( screen,BLUE,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )


def DrawGrid( n_squares_in_row,line_thickness,square_width,square_height ):
    for i in range( 1,n_squares_in_row ):
        pygame.draw.line( screen,BLACK,( i * square_width,0 ),( i * square_width,screen_height ),line_thickness )

    for i in range( 1,n_squares_in_row ):
        pygame.draw.line( screen,BLACK,( 0,i * square_height ),( screen_height,i * square_width ),line_thickness )

    pygame.draw.line( screen,BLACK,( 0,0 ),( 0,screen_height ),line_thickness )
    pygame.draw.line( screen,BLACK,( 0,0 ),( screen_width,0 ),line_thickness )
    pygame.draw.line( screen,BLACK,( screen_width,0 ),( screen_width,screen_height ),line_thickness )
    pygame.draw.line( screen,BLACK,( 0,screen_height ),( screen_width,screen_height ),line_thickness )


def DrawStartScreen():
    end = False

    while not end:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    end = True
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        screen.fill( BLACK )

        DrawText( "The Flash Game - Created by Marek Borik",fontsize * 1.4,WHITE,screen_width * 0.5,screen_height * 0.05 )

        DrawText( "This game will test your subconscious perception.",fontsize,WHITE,screen_width * 0.5,screen_height * 0.2 )
        DrawText( ( "You will be shown a grid of red and blue squares " + str( rounds ) + " times." ),fontsize,WHITE,screen_width * 0.5, screen_height * 0.25 )
        DrawText( "Your task is to determine if you saw more red or blue circles.",fontsize,WHITE,screen_width * 0.5, screen_height * 0.3 )

        DrawText( "If you see more:",fontsize,WHITE,screen_width * 0.3,screen_height * 0.45 )
        DrawText( "If you see more:",fontsize,WHITE,screen_width * 0.7,screen_height * 0.45 )

        pygame.draw.rect( screen,RED,( screen_width * 0.2, screen_height * 0.5,screen_width * 0.2,screen_height * 0.2 ),0 )
        pygame.draw.rect( screen,BLUE,( screen_width * 0.6, screen_height * 0.5,screen_width * 0.2,screen_height * 0.2 ),0 )

        DrawText( "Press Left Arrow",fontsize,WHITE,screen_width * 0.3,screen_height * 0.75 )
        DrawText( "Press Right Arrow",fontsize,WHITE,screen_width * 0.7,screen_height * 0.75 )

        DrawText( "Press spacebar to start",fontsize,WHITE,screen_width * 0.5,screen_height * 0.93 )


        pygame.display.update()


def DoRound():
    left_arrow = False
    right_arrow = False
    turn = False

    #if the windows isn't square, then squares are not squares and we need to treat them like rectangles
    square_width = screen_width / n_squares_in_row
    square_height = screen_height / n_squares_in_row

    color_info,n_red,n_blue = GenerateColorInfo( n_squares_in_row )

    screen.fill( BLACK )
    pygame.display.update()

    sleep( wait_duration )

    #flicker squares for the flash duration

    DrawSquares( n_squares_in_row,color_info,square_width,square_height )
    DrawGrid( n_squares_in_row,line_thickness,square_width,square_height )

    pygame.display.update()

    sleep( flash_duration )
    screen.fill( BLACK )
    pygame.display.update()

    while not turn: # after flash wait for the turn to be completed by pressing either arrow to indicate the answer
       for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    left_arrow = True
                    turn = True
                if event.key == pygame.K_RIGHT:
                    right_arrow = True
                    turn = True

            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

    if n_red >= n_blue and left_arrow == True:  #if the arrow coresponds to the correct answer, return 1, else 0
        return 1

    elif n_blue >= n_red and right_arrow == True:
        return 1

    else:
        return 0


def Game():
   guesses = []

    for i in range( rounds ):
        guesses.append( DoRound() )

    return guesses.count( 1 ) #count ones, meaning correct answers


def EndScreen( correct ):
    screen.fill( BLACK )

    DrawText( "You got " + str( correct ) + " / " + str(  rounds ) + " correct!",fontsize * 2,WHITE,screen_width * 0.5,screen_height * 0.5 )

    pygame.display.update()

    end = False

    while not end:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    end = True
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()


DrawStartScreen()
correct = Game()
EndScreen( correct )
pygame.quit()
quit()
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-10-04 13:42:26

在关注点分离方面做得好

我很高兴看到一个只处理逻辑的函数,还有一些处理绘图和交互的函数。它使我很容易测试,分析和简化它。

generate_color_info

这一职能过于复杂和冗长,难以简化其任务。

  • not5050变量不是必需的(您可以直接使用该条件)。
  • 使用详细的显式循环代替列表理解。
  • 内置的list.count被忽略了。

我首先编写了一个测试(用doctest运行),然后更简单地重新实现它:

代码语言:javascript
复制
def GenerateColorInfo( n_squares_in_row ):
    """
    >>> random.seed(0)
    >>> GenerateColorInfo( 5 )
    ([1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0], 10, 16)
    """
    while True:
        randoms = [random.randint(0, 1) for _ in range(n_squares_in_row ** 2 + 1)]
        if randoms.count(0) != randoms.count(1):
            break
    return randoms, randoms.count(0), randoms.count(1)

列表理解在Game

中的应用

Game不必要地长:

代码语言:javascript
复制
def Game():
    return [DoRound() for _ in range( rounds )].count(True)

布尔化简

代码语言:javascript
复制
if n_red >= n_blue and left_arrow == True:  #if the arrow coresponds to the correct answer, return 1, else 0
    return 1

elif n_blue >= n_red and right_arrow == True:
    return 1

else:
    return 0

是相同的

代码语言:javascript
复制
return (n_red >= n_blue and left_arrow) or \
       (n_blue >= n_red and right_arrow)

但是第二种方法显然更简单(而且它更好,因为它返回True / False而不是10,从而使它更加清楚,它是一个布尔函数)。

用户

的任意内存任务

右箭头和左箭头是如何分配给红色和蓝色的?让用户输入R ( Red )和B ( Blue )更合理。这样,连接是显而易见的,用户不需要使用内存。

代码处理矩形吗?

你的一些代码似乎是用来处理矩形的:

代码语言:javascript
复制
#if the windows isn't square, then squares are not squares and we need to treat them like rectangles
square_width = screen_width / n_squares_in_row
square_height = screen_height / n_squares_in_row

其他代码意味着正方形网格:

代码语言:javascript
复制
def DrawSquares( n_squares_in_row,color_info,square_width,square_height ):
    for i in range( n_squares_in_row ):
        for j in range( n_squares_in_row ):
            if color_info[ i * n_squares_in_row + j ] == 0:
                pygame.draw.rect( screen,RED,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )
            else:
                pygame.draw.rect( screen,BLUE,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )

请要么编写所有的代码来容纳矩形,要么一点也不写,只是其中的一些代码会造成复杂性和混乱,而不会带来任何好处。

重复

您的代码多次声明相同的概念:

代码语言:javascript
复制
            if color_info[ i * n_squares_in_row + j ] == 0:
                pygame.draw.rect( screen,RED,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )
            else:
                pygame.draw.rect( screen,BLUE,( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )

ifelseBLUERED作为颜色外是相等的。干原理是软件开发中最重要的原理之一。

下面是如何修复复制:

代码语言:javascript
复制
        color = RED if color_info[ i * n_squares_in_row + j ] == 0 else BLUE
        pygame.draw.rect( screen, color, ( j * square_width,i * square_height,j * square_width + square_width,i * square_height + screen_height ),0 )

现在只调用一次绘图代码,很明显,只有颜色发生了变化。

代码语言:javascript
复制
pygame.draw.line( screen,BLACK,( 0,0 ),( 0,screen_height ),line_thickness )
pygame.draw.line( screen,BLACK,( 0,0 ),( screen_width,0 ),line_thickness )
pygame.draw.line( screen,BLACK,( screen_width,0 ),( screen_width,screen_height ),line_thickness )
pygame.draw.line( screen,BLACK,( 0,screen_height ),( screen_width,screen_height ),line_thickness )

在这个代码块中,段pygame.draw.line( screen,BLACK, ... line_thickness)被重复4次。只有起点和终点发生变化,所以我们可以使用一个循环:

代码语言:javascript
复制
for (start, end) in [ ( ( 0,0 ),( 0,screen_height) ),
                      ( ( 0,0 ),( screen_width,0 ) ),
                      (( screen_width,0 ),( screen_width,screen_height )),
                      (( 0,screen_height ),( screen_width,screen_height )) ]:
    pygame.draw.line(screen, BLACK, start, end, line_thickness)

DrawText fontsizefontsizecolorWHITE时,可以将其定义为关键字默认参数,以减少重复,从而在需要其他颜色时显式化。

这些代码块类似:

代码语言:javascript
复制
while not turn: # after flash wait for the turn to be completed by pressing either arrow to indicate the answer
   for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                left_arrow = True
                turn = True
            if event.key == pygame.K_RIGHT:
                right_arrow = True
                turn = True

        if event.type == pygame.QUIT:
            pygame.quit()
            quit()

代码语言:javascript
复制
while not end:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                end = True
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()

应该可以编写一个函数一次,并使用它两次。

命名/间距

您可以称它为次要的,但是Python (PEP8)有一个非常广泛采用的样式指南,说明常量应该是ALL_UPPERCASE和所有其他名称lowercase_with_underscores。它有助于提高程序之间的一致性。我建议在您的代码上运行autopep8,以修正间距,使之与广泛接受的样式保持一致。

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

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

复制
相关文章

相似问题

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