显示列表中的某个元素

时间:2013-10-30 14:59:16

标签: python list selection

现在我们的代码从左上角开始创建一个网格,并从左到右逐行填充行和列。目前,它可以从中挑选出一堆图像。它使用一些在形状和形状之间进行选择的IF语句来设置。我想弄清楚怎么做是改变代码所以而不是选择一个随机的rareshape,我可以决定rareshape产生什么。对于Python来说还是新手并且从其他语言中找到许多对我有意义的小东西在Python中不起作用所以它会让我失望一点。

编辑:

这是完整的代码。感谢cactusbin编写的基本代码并由Gareth Rees修订。

import pygame, random, time, sys
from pygame.locals import *
import itertools
import os

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

SHAPE_WIDTH = 64                # Width of each shape (pixels).
SHAPE_HEIGHT = 64               # Height of each shape (pixels).
PUZZLE_COLUMNS = 10              # Number of columns on the board.
PUZZLE_ROWS = 11                # Number of rows on the board.
MARGIN = 118                     # Margin around the board (pixels).
WINDOW_WIDTH = PUZZLE_COLUMNS * SHAPE_WIDTH + 2 * MARGIN + 485
WINDOW_HEIGHT = PUZZLE_ROWS * SHAPE_HEIGHT + 2 * MARGIN - 150
FONT_SIZE = 60
TEXT_OFFSET = MARGIN + 950

# Map from number of matches to points scored.
MINIMUM_MATCH = 10
EXTRA_LENGTH_POINTS = .1
RANDOM_POINTS = .3
DELAY_PENALTY_SECONDS = 1
DELAY_PENALTY_POINTS = 0

FPS = 30
EXPLOSION_SPEED = 15            # In frames per second.
SPIN_SPEED = 15
REFILL_SPEED = 10               # In cells per second.

VERTICAL = False

class Cell(object):
"""
A cell on the board, with properties:
`image` -- a `Surface` object containing the sprite to draw here.
`offset` -- vertical offset in pixels for drawing this cell.
"""
def __init__(self, image):
    self.offset = 0.0
    self.image = image

def tick(self, dt):
    self.offset = max(0.0, self.offset - dt * REFILL_SPEED)

class Board(object):
"""
A rectangular board of cells, with properties:
`w` -- width in cells.
`h` -- height in cells.
`size` -- total number of cells.
`board` -- list of cells.
`matches` -- list of matches, each being a list of exploding cells.
`refill` -- list of cells that are moving up to refill the board.
`score` -- score due to chain reactions.
"""
def __init__(self, width, height):
    self.explosion = [pygame.image.load('images/explosion{}.png'.format(i))
                      for i in range(1, 7)]
    self.spin = [pygame.image.load('images/powerframe{}.png'.format(i))
                  for i in range (1, 12)]
    self.image_color = {}
    self.shapes = []
    self.rareshapes = []

    colors = 'red blue yellow'
    letters = 'acgtu'

    for c in colors.split():
        im = pygame.image.load('images/{}.png'.format(c))
        self.shapes.append(im)
        self.image_color[im] = c
        for l in letters:
            im = pygame.image.load('rareimages/{}{}.png'.format(c, l))
            self.rareshapes.append(im)
            self.image_color[im] = l

    self.background = pygame.image.load("images/bg.png")
    self.blank = pygame.image.load("images/blank.png")
    self.x = pygame.image.load("images/x.png")
    self.w = width
    self.h = height
    self.size = width * height
    self.board = [Cell(self.blank) for _ in range(self.size)]
    self.matches = []
    self.refill = []
    self.score = 0.0
    self.spin_time = 15


def randomize(self):
    """
    Replace the entire board with fresh shapes.
    """
    rare_shapes = [1, 9, 23, 27, 40, 42, 50, 56, 70, 81, 90]

    for i in range(self.size):
        if i in rare_shapes:
            self.board[i] = Cell(random.choice(self.rareshapes))
        else:
            self.board[i] = Cell(random.choice(self.shapes))

def pos(self, i, j):
    """
    Return the index of the cell at position (i, j).
    """
    assert(0 <= i < self.w)
    assert(0 <= j < self.h)
    return j * self.w + i

def busy(self):
    """
    Return `True` if the board is busy animating an explosion or a
    refill and so no further swaps should be permitted.
    """
    return self.refill or self.matches

def tick(self, dt):
    """
    Advance the board by `dt` seconds: move rising blocks (if
    any); otherwise animate explosions for the matches (if any);
    otherwise check for matches.
    """
    if self.refill:
        for c in self.refill:
            c.tick(dt)
        self.refill = [c for c in self.refill if c.offset > 0]
        if self.refill:
            return
    elif self.matches:
        self.explosion_time += dt
        f = int(self.explosion_time * EXPLOSION_SPEED)
        if f < len(self.explosion):
            self.update_matches(self.explosion[f])
            return
        self.update_matches(self.blank)
        self.refill = list(self.refill_columns())
    self.explosion_time = 0
    self.matches = self.find_matches()

def draw(self, display):
    """
    Draw the board on the pygame surface `display`.
    """
    display.blit(self.background, (0, 0))
    for i, c in enumerate(self.board):
        display.blit(c.image,
                     (MARGIN + SHAPE_WIDTH * (i % self.w),
                      MARGIN + SHAPE_HEIGHT * (i // self.w - c.offset) - 68))
    display.blit(self.x, (995, 735))
    display.blit(self.x, (1112, 735))
    display.blit(self.x, (1228, 735))

def swap(self, cursor):
    """
    Swap the two board cells covered by `cursor` and update the
    matches.
    """
    i = self.pos(*cursor)
    b = self.board
    b[i], b[i+1] = b[i+1], b[i]
    self.matches = self.find_matches()


def find_matches(self):
    """
    Search for matches (lines of cells with identical images) and
    return a list of them, each match being represented as a list
    of board positions.
    """
    def lines():
        for j in range(self.h):
            yield range(j * self.w, (j + 1) * self.w)
        for i in range(self.w):
            yield range(i, self.size, self.w)
    def key(i):
        return self.image_color.get(self.board[i].image)
    def matches():
        for line in lines():
            for _, group in itertools.groupby(line, key):
                match = list(group)
                if len(match) >= MINIMUM_MATCH:
                    yield match
                    self.score = self.score + 1
    return list(matches())

def update_matches(self, image):
    """
    Replace all the cells in any of the matches with `image`.
    """
    for match in self.matches:
        for position in match:
            self.board[position].image = image

def refill_columns(self):
    """
    Move cells downwards in columns to fill blank cells, and
    create new cells as necessary so that each column is full. Set
    appropriate offsets for the cells to animate into place.
    """
    for i in range(self.w):
        target = self.size - i - 1
        for pos in range(target, -1, -self.w):
            if self.board[pos].image != self.blank:
                c = self.board[target]
                c.image = self.board[pos].image
                c.offset = (target - pos) // self.w
                target -= self.w
                yield c
        offset = 1 + (target - pos) // self.w
        for pos in range(target, -1, -self.w):
            c = self.board[pos]
            c.image = random.choice(self.shapes)
            c.offset = offset
            yield c

class Game(object):
"""
The state of the game, with properties:
`clock` -- the pygame clock.
`display` -- the window to draw into.
`font` -- a font for drawing the score.
`board` -- the board of cells.
`cursor` -- the current position of the (left half of) the cursor.
`score` -- the player's score.
`last_swap_ticks` -- 
`swap_time` -- time since last swap (in seconds).
"""
def __init__(self):
    pygame.init()
    pygame.display.set_caption("Nucleotide")
    self.clock = pygame.time.Clock()
    self.display = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT),
                                           DOUBLEBUF)
    self.board = Board(PUZZLE_COLUMNS, PUZZLE_ROWS)
    self.font = pygame.font.Font(None, FONT_SIZE)

def start(self):
    """
    Start a new game with a random board.
    """
    self.board.randomize()
    self.cursor = [0, 0]
    self.score = 0.0
    self.swap_time = 125

def quit(self):
    """
    Quit the game and exit the program.
    """
    pygame.quit()
    sys.exit()

def play(self):
    """
    Play a game: repeatedly tick, draw and respond to input until
    the QUIT event is received.
    """
    self.start()
    while True:
        self.draw()
        dt = min(self.clock.tick(FPS) / 1000, 1 / FPS)
        self.swap_time -= dt
        for event in pygame.event.get():
            if event.type == KEYUP:
                self.input(event.key)
            elif event.type == QUIT:
                self.quit()
            elif self.swap_time == 0:
                self.quit()
        self.board.tick(dt)

def input(self, key):
    """
    Respond to the player pressing `key`.
    """
    if key == K_q:
        self.quit()
    elif key == K_RIGHT and self.cursor[0] < self.board.w - 2:
        self.cursor[0] += 1
    elif key == K_LEFT and self.cursor[0] > 0:
        self.cursor[0] -= 1
    elif key == K_DOWN and self.cursor[1] < self.board.h - 1:
        self.cursor[1] += 1
    elif key == K_UP and self.cursor[1] > 0:
        self.cursor[1] -= 1
    elif key == K_SPACE and not self.board.busy():
        self.swap()

def swap(self):
    """
    Swap the two cells under the cursor and update the player's score.
    """
    self.board.swap(self.cursor)

def draw(self):
    self.board.draw(self.display)
    self.draw_score()
    self.draw_time()
    if VERTICAL == False:
        self.draw_cursor()
    elif VERTICAL == True:
        self.draw_cursor2()
    pygame.display.update()

def draw_time(self):
    s = int(self.swap_time)
    text = self.font.render(str(int(s/60)) + ":" + str(s%60).zfill(2),
                            True, BLACK)
    self.display.blit(text, (TEXT_OFFSET, WINDOW_HEIGHT - 170))

def draw_score(self):
    total_score = self.score

def draw_cursor(self):
    topLeft = (MARGIN + self.cursor[0] * SHAPE_WIDTH,
            MARGIN + self.cursor[1] * SHAPE_HEIGHT - 68)
    topRight = (topLeft[0] + SHAPE_WIDTH * 2, topLeft[1])
    bottomLeft = (topLeft[0], topLeft[1] + SHAPE_HEIGHT)
    bottomRight = (topRight[0], topRight[1] + SHAPE_HEIGHT)
    pygame.draw.lines(self.display, WHITE, True,
            [topLeft, topRight, bottomRight, bottomLeft], 3)

if __name__ == '__main__':
    Game().play()

2 个答案:

答案 0 :(得分:1)

如果您要求的是一种更容易指定rareshapecount间隔的方法,您应该放置罕见的形状而不是正常的形状,以下方法更具可读性:

def randomize(self):
   """
   Replace the entire board with fresh shapes.
   """
   # locations we want to place a rare shape
   rare_shapes = [9, 23, 27]

   for i in range(self.size):
      if i in rare_shapes:
         self.board[i] = Cell(random.choice(self.rareshapes))
      else:
         self.board[i] = Cell (random.choice(self.shapes))

可选地,如果您不想每次都对这些间隔进行硬编码,那么您可以随机填充rare_shapes,从而获得更多样化的体验(即,如果您正在设计游戏或类似的东西)。

答案 1 :(得分:0)

你的意思是“我可以决定什么样的rasthape产生而不是选择一个随机的rareshape”我不清楚。你愿意提供更多解释吗?就像你怎么告诉程序使用哪个rareshape?

与此同时,这里有一个更加pythonic版本的代码:

def randomize(self):
    """
    Replace the entire board with fresh shapes.
    """

    specials = dict((x, self.rareshapes) for x in (9, 23, 27))
    get_shape_source = lambda x: specials.get(x, self.shapes) 

    for i in xrange(min(self.size, 41)):
        self.board[i] = Cell(random.choice(get_shape_source(i)))

请注意,如果len(self.board) < min(self.size, 41),这会破坏,但这仍然是您当前代码所做的。

编辑:给出你的评论,明确选择哪个rareshape去哪里的明显方法是明确地将图像与斑点相关联。现在最好的方法是什么/最好的地方配置这真的取决于你的整个代码或至少比你发布的更多。作为一个非常简单和最小的例子,你可以这样做:

from collections import ordereddict

def load_images(self)  
    self.image_color = {}
    self.shapes = []
    self.rareshapes = ordereddict()

    colors = 'red',  'blue', 'yellow'
    letters = 'acgtu'

    for c in colors:
        im = pygame.image.load('images/{}.png'.format(c))
        self.shapes.append(im)
        self.image_color[im] = c
        for l in letters:
            im = pygame.image.load('rareimages/{}{}.png'.format(c, l))
            self.rareshapes.[(c, l)] = im
            self.image_color[im] = l

def randomize(self):
    """
    Replace the entire board with fresh shapes.
    """

    raremap = {
       # spot index : rareshape
       9: ('red', 'a')],  
       23: ('blue', 'u'), 
       27: ('yellow', 'g') 
       }

    for i in xrange(self.size):
        if i in raremap:
            im = self.rareshapes[raremap[i]]
        else:
            im = random.choice(self.shapes)
        self.board[i] = Cell(im)

但从长远来看,这将是不可维护的 - 太多硬编码的东西,以及从一种方法泄漏到另一种方法的太多知识。我不知道'self'是什么样的实例,但你应该考虑拆分责任,这样你就可以在一个类中拥有不变的部分,而在另一个类中拥有“configration”(图像加载,斑点/ rareshapes映射等)。想到的一些设计模式是TemplateMethod(你有一个带有不变部分的抽象基类和实现“配置”部分的具体子类),Builder,当然还有Strategy(在你的情况下,“策略”类会照顾配置)。