创建类俄罗斯方块(Tetris-like)自定义形状的高效网格生成方法咨询
Great question! When you're scaling to 10+ base Tetris shapes with all rotations and mirrors, manual definition like your current approaches gets really tedious and error-prone. Let's break down more efficient, scalable ways to handle this:
First, let's critique your existing approaches
- 方案一(5x5字符网格): Super intuitive for visualization, but wildly redundant—most entries are just
.placeholders. Storing 25 characters per variant wastes space, and manually editing all 80 variants is a recipe for typos. - 方案二(index lists): More compact than the grid approach, but you still have to manually define every rotation/mirror variant. For 10 base shapes, that's 80 manual lists to maintain—no fun.
Better approach: Core coordinate + algorithmic transformation
The most efficient way is to define each base shape using its minimal bounding box coordinates (no empty space), then write simple functions to generate rotations and mirrors automatically. This cuts your manual work down to just 10 base definitions, and the rest is handled by code.
Step 1: Define base shapes with minimal coordinates
Instead of full grids or arbitrary indices, use relative (x,y) coordinates for each block in the shape's smallest possible bounding box. For example:
# Base L-shape: minimal 3x2 bounding box base_L = [(0, 0), (1, 0), (2, 0), (2, 1)]
This is way more compact—only 4 coordinate pairs instead of 25 characters or 4 indices per base shape.
Step 2: Write rotation/mirror functions
These functions take a coordinate list and return the transformed version, adjusting coordinates to keep everything in non-negative values:
def rotate_clockwise(coords): # Rotate 90 degrees clockwise: (x,y) → (y, -x) rotated = [(y, -x) for x, y in coords] # Shift coordinates so the top-left corner is at (0,0) min_x = min(p[0] for p in rotated) min_y = min(p[1] for p in rotated) return [(x - min_x, y - min_y) for x, y in rotated] def mirror_horizontal(coords): # Flip shape horizontally: (x,y) → (-x, y) mirrored = [(-x, y) for x, y in coords] min_x = min(p[0] for p in mirrored) return [(x - min_x, y) for x, y in mirrored]
Step 3: Generate all variants automatically
For each base shape, generate 4 rotations + 4 mirrored rotations (total 8 variants per base shape):
def generate_all_variants(base_shape): # Generate 4 rotations of the base shape rotations = [] current = base_shape for _ in range(4): rotations.append(current) current = rotate_clockwise(current) # Generate 4 rotations of the mirrored base shape mirrored_base = mirror_horizontal(base_shape) mirrored_rotations = [] current = mirrored_base for _ in range(4): mirrored_rotations.append(current) current = rotate_clockwise(current) return rotations + mirrored_rotations # Generate all 8 variants for L-shape all_L_variants = generate_all_variants(base_L)
Step 4: Convert to your desired format (optional)
If you need to convert these coordinate lists back to your original grid or index formats, add helper functions:
# Convert coordinates to 5x5 grid format (like your scheme 1) def coords_to_5x5_grid(coords): grid = [['.' for _ in range(5)] for _ in range(5)] # Center the shape in the 5x5 grid max_x = max(p[0] for p in coords) max_y = max(p[1] for p in coords) offset_x = (5 - max_x - 1) // 2 offset_y = (5 - max_y - 1) // 2 for x, y in coords: grid[y + offset_y][x + offset_x] = '0' return [''.join(row) for row in grid] # Convert coordinates to 5x5 index format (like your scheme 2, index = x + y*5) def coords_to_5x5_indices(coords): # First center the shape as above, then calculate indices max_x = max(p[0] for p in coords) max_y = max(p[1] for p in coords) offset_x = (5 - max_x - 1) // 2 offset_y = (5 - max_y - 1) // 2 return [x + offset_x + (y + offset_y)*5 for x, y in coords]
Bonus: Bitmask representation (for extreme efficiency)
If you're optimizing for storage or collision detection speed, use integer bitmasks. For a 5x5 grid, each block corresponds to a bit in a 25-bit integer. For example, the base L-shape centered in 5x5 would be:
# Binary: 00000 00000 01000 01110 00000 → converted to integer L_bitmask = 0b0000000000010000111000000
Rotations/mirrors can be handled with bitwise operations or coordinate-to-bitmask conversion, and this format uses just 4 bytes per variant—way more compact than grids or coordinate lists.
This approach scales perfectly: you only write 10 base shape definitions, and the code handles generating all 80 variants automatically. No more manual list editing, no redundant data, and easy to extend if you add more shapes later.
内容的提问来源于stack exchange,提问作者Cookie




