Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b72e841e9 | ||
|
|
8952753fc3 | ||
|
|
15851cb269 | ||
|
|
5c9b172882 | ||
|
|
fc3d2fc04c | ||
|
|
231c19c7fd | ||
|
|
5cf73ceb7d | ||
|
|
479553424f | ||
|
|
f003cb2d2e | ||
|
|
8c8a1e6de0 | ||
|
|
27e7ad8dc3 |
37
README.md
Normal file
37
README.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Python Tetris Clone
|
||||||
|
|
||||||
|
The python-tetris-clone project was created for the purpose of becoming familiar with Python 3. The goal is to replicate the most current version of Tetris (https://tetris.com/play-tetris) down to every mechanic. This includes the way pieces rotate and even newer features such as the ghost piece.
|
||||||
|
|
||||||
|
The game was created using the pygame python library and builds on Github are packaged into one executable using cx_Freeze.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Make sure you have installed Python 3. If you have not, download and install Python 3 at [python.org](https://www.python.org/downloads/).
|
||||||
|
|
||||||
|
Then use the package manager [pip](https://pip.pypa.io/en/stable/) to install the required packages.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install pygame
|
||||||
|
pip install pyyaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run the Game
|
||||||
|
|
||||||
|
Clone the Github repository. From your terminal move to the root of the project and run the following line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
In some systems you may need to run this instead:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
||||||
64
Tetris.py
64
Tetris.py
@@ -1,12 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import pygame
|
import pygame
|
||||||
|
from pygame import mixer
|
||||||
|
|
||||||
from util.ConfigurationManager import ConfigurationManager
|
from util.ConfigurationManager import ConfigurationManager
|
||||||
from util.PieceGenerator import PieceGenerator
|
from util.PieceGenerator import PieceGenerator
|
||||||
from entity.Well import Well
|
from entity.Well import Well
|
||||||
from entity.Stack import Stack
|
from entity.Stack import Stack
|
||||||
|
|
||||||
# TODO should be a singleton?
|
# TODO should be a singleton and refactor the whole file?
|
||||||
class Tetris:
|
class Tetris:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -14,12 +15,14 @@ class Tetris:
|
|||||||
self.tile_size = -1
|
self.tile_size = -1
|
||||||
self.screen = None
|
self.screen = None
|
||||||
self.clock = None
|
self.clock = None
|
||||||
|
self.main_music = None
|
||||||
self.current_piece = None
|
self.current_piece = None
|
||||||
self.well = None
|
self.well = None
|
||||||
self.stack = None
|
self.stack = None
|
||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
pygame.init()
|
pygame.init()
|
||||||
|
mixer.init()
|
||||||
|
|
||||||
win_width = ConfigurationManager.configuration["window"]["width"]
|
win_width = ConfigurationManager.configuration["window"]["width"]
|
||||||
win_height = ConfigurationManager.configuration["window"]["height"]
|
win_height = ConfigurationManager.configuration["window"]["height"]
|
||||||
@@ -30,20 +33,35 @@ class Tetris:
|
|||||||
self.tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
self.tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
self.screen = pygame.display.set_mode((win_width, win_height))
|
self.screen = pygame.display.set_mode((win_width, win_height))
|
||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
self.well = Well((280, 80), ConfigurationManager.configuration["color"]["border"]) # TODO calculate position later and redo color config for well
|
self.main_music = mixer.Channel(0)
|
||||||
self.stack = Stack(ConfigurationManager.configuration["color"]["base-4"], ConfigurationManager.configuration["color"]["border"])
|
self.well = Well((280, 80), ConfigurationManager.configuration["color"]["well-1"], ConfigurationManager.configuration["color"]["well-border-1"]) # TODO calculate position later and redo color config for well
|
||||||
|
self.stack = Stack(ConfigurationManager.configuration["color"]["stack-1"], ConfigurationManager.configuration["color"]["stack-border-1"])
|
||||||
|
|
||||||
loaded_icon = pygame.image.load(win_icon)
|
loaded_icon = pygame.image.load(win_icon)
|
||||||
pygame.display.set_caption(win_title)
|
pygame.display.set_caption(win_title)
|
||||||
pygame.display.set_icon(loaded_icon)
|
pygame.display.set_icon(loaded_icon)
|
||||||
|
|
||||||
|
self.is_pressing_down = False # TODO move into control util later
|
||||||
|
|
||||||
|
main_music_file = ConfigurationManager.configuration["sound"]["main-music"]
|
||||||
|
self.main_music.set_volume(0.7) # TODO add volume to the config
|
||||||
|
self.main_music.play(mixer.Sound(main_music_file), -1)
|
||||||
|
|
||||||
# gets called from the games main loop
|
# gets called from the games main loop
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
# TODO write not initialized exception
|
# TODO write not initialized exception
|
||||||
elapsed_time = self.clock.tick(self.fps)
|
elapsed_time = self.clock.tick(self.fps)
|
||||||
|
|
||||||
if self.current_piece:
|
if self.current_piece:
|
||||||
self.current_piece.update(elapsed_time, self.well, self.stack)
|
self.current_piece.update(elapsed_time, self)
|
||||||
|
else:
|
||||||
|
self.current_piece = PieceGenerator.get_piece((360, 100)) # TODO calculate spawn position
|
||||||
|
if self.stack and self.current_piece.collide(self.stack):
|
||||||
|
pygame.quit()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if self.stack:
|
||||||
|
self.stack.update(elapsed_time)
|
||||||
|
|
||||||
# TODO create control utility class
|
# TODO create control utility class
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
@@ -70,43 +88,39 @@ class Tetris:
|
|||||||
self.current_piece.revert()
|
self.current_piece.revert()
|
||||||
if self.stack and self.current_piece.collide(self.stack):
|
if self.stack and self.current_piece.collide(self.stack):
|
||||||
self.current_piece.revert()
|
self.current_piece.revert()
|
||||||
if event.key == pygame.K_UP:
|
|
||||||
self.current_piece.move((0, -self.tile_size))
|
|
||||||
if self.well and self.current_piece.collide(self.well):
|
|
||||||
self.current_piece.revert()
|
|
||||||
if self.stack and self.current_piece.collide(self.stack):
|
|
||||||
self.current_piece.revert()
|
|
||||||
if event.key == pygame.K_DOWN:
|
if event.key == pygame.K_DOWN:
|
||||||
self.current_piece.move((0, self.tile_size))
|
self.is_pressing_down = True
|
||||||
if self.well and self.current_piece.collide(self.well):
|
if self.current_piece:
|
||||||
self.current_piece.revert()
|
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
|
||||||
if self.stack and self.current_piece.collide(self.stack):
|
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
|
||||||
self.current_piece.revert()
|
if event.type == pygame.KEYUP:
|
||||||
if event.key == pygame.K_z:
|
if event.key == pygame.K_DOWN:
|
||||||
|
self.is_pressing_down = False
|
||||||
if self.current_piece:
|
if self.current_piece:
|
||||||
self.stack.add_piece(self.current_piece)
|
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
|
||||||
self.__generate_piece((300, 100))
|
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
|
||||||
|
|
||||||
|
if self.is_pressing_down:
|
||||||
|
if self.current_piece:
|
||||||
|
self.current_piece.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"] / 8
|
||||||
|
self.current_piece.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"] / 8
|
||||||
|
|
||||||
|
|
||||||
def draw(self) -> None:
|
def draw(self) -> None:
|
||||||
# TODO write not initialized exception
|
# TODO write not initialized exception
|
||||||
|
|
||||||
# draw window bg
|
# draw window bg
|
||||||
bg_color = pygame.Color(ConfigurationManager.configuration["window"]["bg-color"])
|
bg_color = pygame.Color(ConfigurationManager.configuration["color"]["window-bg"])
|
||||||
self.screen.fill(bg_color)
|
self.screen.fill(bg_color)
|
||||||
|
|
||||||
# draw all game objects
|
# draw all game objects
|
||||||
if self.current_piece:
|
|
||||||
self.current_piece.draw(self.screen)
|
|
||||||
if self.well:
|
if self.well:
|
||||||
self.well.draw(self.screen)
|
self.well.draw(self.screen)
|
||||||
if self.stack:
|
if self.stack:
|
||||||
self.stack.draw(self.screen)
|
self.stack.draw(self.screen)
|
||||||
|
if self.current_piece:
|
||||||
|
self.current_piece.draw(self.screen)
|
||||||
|
|
||||||
# update display
|
# update display
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
|
|
||||||
# TODO one line method is questionable
|
|
||||||
def __generate_piece(self, position):
|
|
||||||
self.current_piece = PieceGenerator.get_piece(position)
|
|
||||||
|
|
||||||
7
build.py
7
build.py
@@ -9,7 +9,7 @@ if sys.platform == 'win32':
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="Tetris",
|
name="Tetris",
|
||||||
version="0.1.0",
|
version="0.4.0",
|
||||||
description="Tetris Python Clone",
|
description="Tetris Python Clone",
|
||||||
options={
|
options={
|
||||||
"build_exe": {
|
"build_exe": {
|
||||||
@@ -30,7 +30,10 @@ setup(
|
|||||||
],
|
],
|
||||||
"include_files": [
|
"include_files": [
|
||||||
"config.yaml",
|
"config.yaml",
|
||||||
"tetris_icon.png"
|
"tetris_icon.png",
|
||||||
|
"main_music.ogg",
|
||||||
|
"piece_set_3.wav",
|
||||||
|
"row_completion.wav"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
24
config.yaml
24
config.yaml
@@ -3,16 +3,26 @@ window:
|
|||||||
height: 600
|
height: 600
|
||||||
icon: "tetris_icon.png"
|
icon: "tetris_icon.png"
|
||||||
title: "Tetris"
|
title: "Tetris"
|
||||||
bg-color: "#6495ED" # cornflower-blue
|
|
||||||
|
|
||||||
|
sound:
|
||||||
|
main-music: "main_music.ogg"
|
||||||
|
row-completion: "row_completion.wav"
|
||||||
|
piece-set: "piece_set_3.wav"
|
||||||
|
|
||||||
engine:
|
engine:
|
||||||
fps: 60
|
fps: 60
|
||||||
tile-size: 20
|
tile-size: 20
|
||||||
|
piece-gravity-time: 400
|
||||||
|
piece-set-time: 600
|
||||||
|
|
||||||
# https://coolors.co/6495ed-ee6352-59cd90-fac05e-dfd9e2
|
|
||||||
color:
|
color:
|
||||||
base-1: "#EE6352"
|
window-bg: "#000000"
|
||||||
base-2: "#59CD90"
|
piece-1: "#1F37EC"
|
||||||
base-3: "#FAC05E"
|
piece-2: "#3DBBFC"
|
||||||
base-4: "#4C5B5C"
|
piece-3: "#FFFFFF"
|
||||||
border: "#DFD9E2"
|
piece-inner-border-1: "#1F37EC"
|
||||||
|
piece-border-1: "#000000"
|
||||||
|
well-1: "#9BFCF0"
|
||||||
|
well-border-1: "#000000"
|
||||||
|
stack-1: "#747474"
|
||||||
|
stack-border-1: "#000000"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
from pygame import mixer
|
||||||
|
import pygame
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from entity.Entity import Entity
|
from entity.Entity import Entity
|
||||||
@@ -9,28 +11,58 @@ from util.ConfigurationManager import ConfigurationManager
|
|||||||
https://tetris.fandom.com/wiki/Tetromino
|
https://tetris.fandom.com/wiki/Tetromino
|
||||||
'''
|
'''
|
||||||
class Piece(Entity):
|
class Piece(Entity):
|
||||||
|
|
||||||
GRAVITY = 800 # A move down every 800 ms
|
|
||||||
|
|
||||||
def __init__(self, shape: Tuple, position: Tuple, color: str, border_color: str):
|
def __init__(self, shape: Tuple, position: Tuple, color: str, inner_border_color: str, border_color: str):
|
||||||
super().__init__(self.__get_points(shape, position), color, border_color)
|
super().__init__(self.__get_points(shape, position), color, border_color)
|
||||||
|
|
||||||
|
self.inner_border_color = inner_border_color
|
||||||
self.center = self.__get_center(shape, position)
|
self.center = self.__get_center(shape, position)
|
||||||
|
self.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
|
||||||
|
self.current_gravity_time = 0
|
||||||
|
self.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
|
||||||
|
self.current_set_time = 0
|
||||||
|
self.piece_set_sound = mixer.Channel(2)
|
||||||
|
|
||||||
self.previous_points = None
|
self.previous_points = None
|
||||||
self.previous_center = None
|
self.previous_center = None
|
||||||
|
|
||||||
def update(self, elapsed_time: int, well: Entity, stack: Entity):
|
def update(self, elapsed_time: int, tetris) -> None:
|
||||||
super().update(elapsed_time)
|
super().update(elapsed_time)
|
||||||
|
|
||||||
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
well = tetris.well
|
||||||
if self.elapsed_time >= Piece.GRAVITY:
|
stack = tetris.stack
|
||||||
self.elapsed_time -= Piece.GRAVITY
|
|
||||||
|
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
|
if self.elapsed_time >= self.gravity_time and self.current_set_time == 0:
|
||||||
|
self.elapsed_time = 0
|
||||||
|
|
||||||
self.move((0, tile_size))
|
self.move((0, tile_size))
|
||||||
if well and self.collide(well):
|
if well and self.collide(well) or stack and self.collide(stack):
|
||||||
self.revert()
|
|
||||||
if stack and self.collide(stack):
|
|
||||||
self.revert()
|
self.revert()
|
||||||
|
self.current_set_time += elapsed_time
|
||||||
|
|
||||||
|
if self.current_set_time > 0:
|
||||||
|
self.current_set_time += elapsed_time
|
||||||
|
|
||||||
|
if self.current_set_time >= self.set_time:
|
||||||
|
self.__play_piece_set_sound()
|
||||||
|
self.current_set_time = 0
|
||||||
|
|
||||||
|
stack.add_piece(self)
|
||||||
|
tetris.current_piece = None
|
||||||
|
|
||||||
|
def draw(self, surface: pygame.Surface) -> None:
|
||||||
|
super().draw(surface)
|
||||||
|
|
||||||
|
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
|
for square in self.points:
|
||||||
|
if self.inner_border_color:
|
||||||
|
vertex_one = (square[0][0] + (tile_size // 10), square[0][1] + (tile_size // 10))
|
||||||
|
vertex_two = (square[1][0] - (tile_size // 10), square[1][1] + (tile_size // 10))
|
||||||
|
vertex_three = (square[2][0] - (tile_size // 10), square[2][1] - (tile_size // 10))
|
||||||
|
vertex_four = (square[3][0] + (tile_size // 10), square[3][1] - (tile_size // 10))
|
||||||
|
new_square = (vertex_one, vertex_two, vertex_three, vertex_four)
|
||||||
|
pygame.draw.polygon(surface, pygame.Color(self.inner_border_color), new_square, max(tile_size // 6, 1))
|
||||||
|
|
||||||
def move(self, vector: Tuple) -> None:
|
def move(self, vector: Tuple) -> None:
|
||||||
# reset elapsed time if user moves down to stall gravity
|
# reset elapsed time if user moves down to stall gravity
|
||||||
@@ -72,6 +104,10 @@ class Piece(Entity):
|
|||||||
self.points = self.previous_points
|
self.points = self.previous_points
|
||||||
self.center = self.previous_center
|
self.center = self.previous_center
|
||||||
|
|
||||||
|
def __play_piece_set_sound(self) -> None:
|
||||||
|
piece_set_sound_file = ConfigurationManager.configuration["sound"]["piece-set"]
|
||||||
|
self.piece_set_sound.play(mixer.Sound(piece_set_sound_file))
|
||||||
|
|
||||||
def __get_points(self, shape: Tuple, position: Tuple) -> List:
|
def __get_points(self, shape: Tuple, position: Tuple) -> List:
|
||||||
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,60 @@
|
|||||||
|
from pygame import mixer
|
||||||
|
|
||||||
|
from util.ConfigurationManager import ConfigurationManager
|
||||||
from entity.Piece import Piece
|
from entity.Piece import Piece
|
||||||
|
from entity.Well import Well
|
||||||
from entity.Entity import Entity
|
from entity.Entity import Entity
|
||||||
|
|
||||||
class Stack(Entity):
|
class Stack(Entity):
|
||||||
|
|
||||||
def __init__(self, color: str, border_color: str):
|
def __init__(self, color: str, border_color: str):
|
||||||
super().__init__([], color, border_color)
|
super().__init__([], color, border_color)
|
||||||
|
self.rows_completed_count = 0
|
||||||
|
self.row_completion_sound = mixer.Channel(1)
|
||||||
|
|
||||||
def add_piece(self, piece: Piece):
|
def update(self, elapsed_time) -> None:
|
||||||
self.points += piece.points
|
super().update(elapsed_time)
|
||||||
|
self.rows_completed_count += self.__complete_rows()
|
||||||
|
|
||||||
|
def add_piece(self, piece: Piece) -> None:
|
||||||
|
self.points += piece.points
|
||||||
|
|
||||||
|
def __complete_rows(self) -> int:
|
||||||
|
squares_by_row = {}
|
||||||
|
for square in self.points:
|
||||||
|
top_left_vertex = square[0]
|
||||||
|
if top_left_vertex[1] not in squares_by_row:
|
||||||
|
squares_by_row[top_left_vertex[1]] = []
|
||||||
|
if square not in squares_by_row[top_left_vertex[1]]:
|
||||||
|
squares_by_row[top_left_vertex[1]].append(square)
|
||||||
|
|
||||||
|
squares_to_exclude = []
|
||||||
|
rows_completed = []
|
||||||
|
for key in squares_by_row:
|
||||||
|
if len(squares_by_row[key]) == Well.WIDTH:
|
||||||
|
squares_to_exclude += squares_by_row[key]
|
||||||
|
rows_completed.append(key)
|
||||||
|
|
||||||
|
if len(squares_to_exclude) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
self.__play_row_completion_sound()
|
||||||
|
|
||||||
|
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
|
new_points = []
|
||||||
|
for square in self.points:
|
||||||
|
if square not in squares_to_exclude:
|
||||||
|
for vertex in square:
|
||||||
|
distance_to_move = 0
|
||||||
|
for row_completed in rows_completed:
|
||||||
|
if vertex[1] <= row_completed:
|
||||||
|
distance_to_move += 1
|
||||||
|
vertex[1] += tile_size * distance_to_move
|
||||||
|
new_points.append(square)
|
||||||
|
self.points = new_points
|
||||||
|
|
||||||
|
return len(rows_completed)
|
||||||
|
|
||||||
|
def __play_row_completion_sound(self) -> None:
|
||||||
|
row_completion_sound_file = ConfigurationManager.configuration["sound"]["row-completion"]
|
||||||
|
self.row_completion_sound.play(mixer.Sound(row_completion_sound_file))
|
||||||
@@ -8,8 +8,8 @@ class Well(Entity):
|
|||||||
WIDTH = 10 # standard tetris well width, should not be changed
|
WIDTH = 10 # standard tetris well width, should not be changed
|
||||||
HEIGHT = 20 # standard tetris well height, should not be changed
|
HEIGHT = 20 # standard tetris well height, should not be changed
|
||||||
|
|
||||||
def __init__(self, position: Tuple, color):
|
def __init__(self, position: Tuple, color: str, border_color: str):
|
||||||
super().__init__(self.__get_points(position), color)
|
super().__init__(self.__get_points(position), color, border_color)
|
||||||
|
|
||||||
def __get_points(self, position: Tuple) -> List:
|
def __get_points(self, position: Tuple) -> List:
|
||||||
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
|
||||||
|
|||||||
BIN
main_music.ogg
Normal file
BIN
main_music.ogg
Normal file
Binary file not shown.
BIN
piece_set_3.wav
Normal file
BIN
piece_set_3.wav
Normal file
Binary file not shown.
BIN
row_completion.wav
Normal file
BIN
row_completion.wav
Normal file
Binary file not shown.
0
util/ControlsManger.py
Normal file
0
util/ControlsManger.py
Normal file
@@ -16,9 +16,8 @@ class PieceGenerator:
|
|||||||
if len(cls.__bucket) == 0:
|
if len(cls.__bucket) == 0:
|
||||||
cls.__generate_bucket()
|
cls.__generate_bucket()
|
||||||
|
|
||||||
border_color = ConfigurationManager.configuration["color"]["border"] # TODO abstract color call to config out?
|
base_color, inner_border_color, border_color = cls.__get_piece_color()
|
||||||
|
return Piece(cls.__get_piece_shape(cls.__bucket.pop()), position, base_color, inner_border_color, border_color)
|
||||||
return Piece(cls.__get_piece_shape(cls.__bucket.pop()), position, cls.__get_piece_color(), border_color)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __generate_bucket(cls) -> None:
|
def __generate_bucket(cls) -> None:
|
||||||
@@ -45,6 +44,11 @@ class PieceGenerator:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __get_piece_color() -> str:
|
def __get_piece_color() -> Tuple:
|
||||||
random_number = random.randint(1, 3)
|
random_number = random.randint(1, 3)
|
||||||
return ConfigurationManager.configuration["color"]["base-" + str(random_number)]
|
|
||||||
|
base_color = ConfigurationManager.configuration["color"]["piece-" + str(random_number)]
|
||||||
|
inner_border_color = None if random_number != 3 else ConfigurationManager.configuration["color"]["piece-inner-border-1"]
|
||||||
|
border_color = ConfigurationManager.configuration["color"]["piece-border-1"]
|
||||||
|
|
||||||
|
return (base_color, inner_border_color, border_color)
|
||||||
|
|||||||
Reference in New Issue
Block a user