简体   繁体   English

在列表中显示特定元素

[英]Display a certain element in a list

Right now our code creates a grid starting at the top left and filling in rows and columns from left to right, row by row. 现在,我们的代码创建了一个从左上角开始的网格,并从左到右逐行填充行和列。 Currently, there are a bunch of images it can pick from. 当前,有很多图像可供选择。 It is set using a handful of IF statements that picks between shapes and rareshapes. 使用少数在形状和稀有形状之间选择的IF语句进行设置。 What I am trying to figure out how to do is change the code so instead of it picking a random rareshape, I can decide what rareshape spawns. 我试图弄清楚该怎么做是更改代码,所以我可以选择生成什么稀有形状,而不是选择随机的稀有形状。 Still new to Python and finding a lot of little things that make sense to me from other languages don't work in Python so its throwing me off a little. 对于Python来说仍然是新事物,并且从其他语言中发现了许多对我有意义的小事情在Python中不起作用,因此它使我有点失望。

EDIT: 编辑:

Here is the full code. 这是完整的代码。 Credit for the base code written by cactusbin and revised by Gareth Rees. 感谢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()

If what you are asking for is a way to more easily specify at which rareshapecount intervals you should place a rare shape instead of a normal shape, the following approach is more readable: 如果您要的是一种更轻松地指定应在哪个稀有形状计数间隔内放置稀有形状而不是普通形状的方法,则以下方法更易读:

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))

Optionally, you could randomly populate rare_shapes if you don't feel like hardcoding the intervals each time, making for a more varied experience (ie, if you're designing a game or something similar). 可选地,如果您不想每次都对间隔进行硬编码,则可以随机填充稀有形状,从而获得更多样化的体验(即,如果您正在设计游戏或类似的东西)。

What you mean by "I can decide what rareshape spawns instead of it picking a random rareshape" is unclear to me. 您不清楚“我可以决定生成哪种稀有形状而不是选择随机的稀有形状”的意思对我不清楚。 Would you care to give more explanations ? 您愿意提供更多解释吗? Like how you would tell the program which rareshape to use ? 就像您如何告诉程序使用哪种稀有形状?

In the meantime, here's a somewhat more pythonic version of your code: 同时,这是您的代码的Python版本:

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)))

Note that this would break if len(self.board) < min(self.size, 41) but well, that's still basically what your current code do. 注意,如果len(self.board) < min(self.size, 41)会中断len(self.board) < min(self.size, 41)但是,基本上,这仍然是您当前代码执行的操作。

edit: given your comment, the obvious way to explicitly choose which rareshape goes where is to explicitly associate images with spots. 编辑:给出您的评论,显式选择显着形状的一种明显方法是显式将图像与斑点相关联。 Now what's the best way to do so / the best place ton configure this really depends on your whole code or at least on more than what you posted. 现在,这样做的最佳方法是什么/配置的最佳位置实际上取决于整个代码,或者至少取决于您发布的内容。 As a very simple and minimal exemple, you could just have this: 作为一个非常简单和最小的示例,您可以这样做:

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)

But it will be just unmaintainable in the long run - too much hardcoded stuff, and too much knowledge leaking from one method to another. 但是,从长远来看,这将是无法维持的-过多的硬编码内容,以及太多的知识从一种方法泄漏到另一种方法。 I don't know what 'self' is an instance of, but you should considered splitting the responsabilities so you have the invariant parts in one class and the "configration" (images to load, spots / rareshapes mapping etc) in another. 我不知道“自我”是什么实例,但是您应该考虑拆分职责,以便一类中具有不变的部分,而另一类中具有“配置”(要加载的图像,斑点/稀有形状映射等)。 Some design patterns that come to mind are TemplateMethod (where you have an abstract base class with the invariant parts and concrete subclasses implementing the "configuration" part), Builder, and of course Strategy (in your case the "Strategy" class would take care of the configuration). 我想到的一些设计模式是TemplateMethod(其中有一个抽象基类,其中包含不变的部分,而具体的子类实现了“ configuration”部分),Builder,当然还有Strategy(在您的情况下,“ Strategy”类将负责)的配置)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM