mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-12-18 09:10:16 +00:00
Added matrix based color game algorithm (#12400)
* Added matrix based color game * updating DIRECTORY.md --------- Co-authored-by: Miranda13 <Miranda13@users.noreply.github.com>
This commit is contained in:
parent
fc33c50593
commit
c792122632
|
@ -794,6 +794,7 @@
|
|||
* [Cramers Rule 2X2](matrix/cramers_rule_2x2.py)
|
||||
* [Inverse Of Matrix](matrix/inverse_of_matrix.py)
|
||||
* [Largest Square Area In Matrix](matrix/largest_square_area_in_matrix.py)
|
||||
* [Matrix Based Game](matrix/matrix_based_game.py)
|
||||
* [Matrix Class](matrix/matrix_class.py)
|
||||
* [Matrix Equalization](matrix/matrix_equalization.py)
|
||||
* [Matrix Multiplication Recursion](matrix/matrix_multiplication_recursion.py)
|
||||
|
|
284
matrix/matrix_based_game.py
Normal file
284
matrix/matrix_based_game.py
Normal file
|
@ -0,0 +1,284 @@
|
|||
"""
|
||||
Matrix-Based Game Script
|
||||
=========================
|
||||
This script implements a matrix-based game where players interact with a grid of
|
||||
elements. The primary goals are to:
|
||||
- Identify connected elements of the same type from a selected position.
|
||||
- Remove those elements, adjust the matrix by simulating gravity, and reorganize empty
|
||||
columns.
|
||||
- Calculate and display the score based on the number of elements removed in each move.
|
||||
|
||||
Functions:
|
||||
-----------
|
||||
1. `find_repeat`: Finds all connected elements of the same type.
|
||||
2. `increment_score`: Calculates the score for a given move.
|
||||
3. `move_x`: Simulates gravity in a column.
|
||||
4. `move_y`: Reorganizes the matrix by shifting columns leftward when a column becomes
|
||||
empty.
|
||||
5. `play`: Executes a single move, updating the matrix and returning the score.
|
||||
|
||||
Input Format:
|
||||
--------------
|
||||
1. Matrix size (`lines`): Integer specifying the size of the matrix (N x N).
|
||||
2. Matrix content (`matrix`): Rows of the matrix, each consisting of characters.
|
||||
3. Number of moves (`movs`): Integer indicating the number of moves.
|
||||
4. List of moves (`movements`): A comma-separated string of coordinates for each move.
|
||||
|
||||
(0,0) position starts from first left column to last right, and below row to up row
|
||||
|
||||
|
||||
Example Input:
|
||||
---------------
|
||||
4
|
||||
RRBG
|
||||
RBBG
|
||||
YYGG
|
||||
XYGG
|
||||
2
|
||||
0 1,1 1
|
||||
|
||||
Example (0,0) = X
|
||||
|
||||
Output:
|
||||
--------
|
||||
The script outputs the total score after processing all moves.
|
||||
|
||||
Usage:
|
||||
-------
|
||||
Run the script and provide the required inputs as prompted.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def validate_matrix_size(size: int) -> None:
|
||||
"""
|
||||
>>> validate_matrix_size(-1)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Matrix size must be a positive integer.
|
||||
"""
|
||||
if not isinstance(size, int) or size <= 0:
|
||||
raise ValueError("Matrix size must be a positive integer.")
|
||||
|
||||
|
||||
def validate_matrix_content(matrix: list[str], size: int) -> None:
|
||||
"""
|
||||
Validates that the number of elements in the matrix matches the given size.
|
||||
|
||||
>>> validate_matrix_content(['aaaa', 'aaaa', 'aaaa', 'aaaa'], 3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: The matrix dont match with size.
|
||||
>>> validate_matrix_content(['aa%', 'aaa', 'aaa'], 3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Matrix rows can only contain letters and numbers.
|
||||
>>> validate_matrix_content(['aaa', 'aaa', 'aaaa'], 3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Each row in the matrix must have exactly 3 characters.
|
||||
"""
|
||||
print(matrix)
|
||||
if len(matrix) != size:
|
||||
raise ValueError("The matrix dont match with size.")
|
||||
for row in matrix:
|
||||
if len(row) != size:
|
||||
msg = f"Each row in the matrix must have exactly {size} characters."
|
||||
raise ValueError(msg)
|
||||
if not all(char.isalnum() for char in row):
|
||||
raise ValueError("Matrix rows can only contain letters and numbers.")
|
||||
|
||||
|
||||
def validate_moves(moves: list[tuple[int, int]], size: int) -> None:
|
||||
"""
|
||||
>>> validate_moves([(1, 2), (-1, 0)], 3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Move is out of bounds for a matrix.
|
||||
"""
|
||||
for move in moves:
|
||||
x, y = move
|
||||
if not (0 <= x < size and 0 <= y < size):
|
||||
raise ValueError("Move is out of bounds for a matrix.")
|
||||
|
||||
|
||||
def parse_moves(input_str: str) -> list[tuple[int, int]]:
|
||||
"""
|
||||
>>> parse_moves("0 1, 1 1")
|
||||
[(0, 1), (1, 1)]
|
||||
>>> parse_moves("0 1, 1 1, 2")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Each move must have exactly two numbers.
|
||||
>>> parse_moves("0 1, 1 1, 2 4 5 6")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Each move must have exactly two numbers.
|
||||
"""
|
||||
moves = []
|
||||
for pair in input_str.split(","):
|
||||
parts = pair.strip().split()
|
||||
if len(parts) != 2:
|
||||
raise ValueError("Each move must have exactly two numbers.")
|
||||
x, y = map(int, parts)
|
||||
moves.append((x, y))
|
||||
return moves
|
||||
|
||||
|
||||
def find_repeat(
|
||||
matrix_g: list[list[str]], row: int, column: int, size: int
|
||||
) -> set[tuple[int, int]]:
|
||||
"""
|
||||
Finds all connected elements of the same type from a given position.
|
||||
|
||||
>>> find_repeat([['A', 'B', 'A'], ['A', 'B', 'A'], ['A', 'A', 'A']], 0, 0, 3)
|
||||
{(1, 2), (2, 1), (0, 0), (2, 0), (0, 2), (2, 2), (1, 0)}
|
||||
>>> find_repeat([['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']], 1, 1, 3)
|
||||
set()
|
||||
"""
|
||||
|
||||
column = size - 1 - column
|
||||
visited = set()
|
||||
repeated = set()
|
||||
|
||||
if (color := matrix_g[column][row]) != "-":
|
||||
|
||||
def dfs(row_n: int, column_n: int) -> None:
|
||||
if row_n < 0 or row_n >= size or column_n < 0 or column_n >= size:
|
||||
return
|
||||
if (row_n, column_n) in visited:
|
||||
return
|
||||
visited.add((row_n, column_n))
|
||||
if matrix_g[row_n][column_n] == color:
|
||||
repeated.add((row_n, column_n))
|
||||
dfs(row_n - 1, column_n)
|
||||
dfs(row_n + 1, column_n)
|
||||
dfs(row_n, column_n - 1)
|
||||
dfs(row_n, column_n + 1)
|
||||
|
||||
dfs(column, row)
|
||||
|
||||
return repeated
|
||||
|
||||
|
||||
def increment_score(count: int) -> int:
|
||||
"""
|
||||
Calculates the score for a move based on the number of elements removed.
|
||||
|
||||
>>> increment_score(3)
|
||||
6
|
||||
>>> increment_score(0)
|
||||
0
|
||||
"""
|
||||
return int(count * (count + 1) / 2)
|
||||
|
||||
|
||||
def move_x(matrix_g: list[list[str]], column: int, size: int) -> list[list[str]]:
|
||||
"""
|
||||
Simulates gravity in a specific column.
|
||||
|
||||
>>> move_x([['-', 'A'], ['-', '-'], ['-', 'C']], 1, 2)
|
||||
[['-', '-'], ['-', 'A'], ['-', 'C']]
|
||||
"""
|
||||
|
||||
new_list = []
|
||||
|
||||
for row in range(size):
|
||||
if matrix_g[row][column] != "-":
|
||||
new_list.append(matrix_g[row][column])
|
||||
else:
|
||||
new_list.insert(0, matrix_g[row][column])
|
||||
for row in range(size):
|
||||
matrix_g[row][column] = new_list[row]
|
||||
return matrix_g
|
||||
|
||||
|
||||
def move_y(matrix_g: list[list[str]], size: int) -> list[list[str]]:
|
||||
"""
|
||||
Shifts all columns leftward when an entire column becomes empty.
|
||||
|
||||
>>> move_y([['-', 'A'], ['-', '-'], ['-', 'C']], 2)
|
||||
[['A', '-'], ['-', '-'], ['-', 'C']]
|
||||
"""
|
||||
|
||||
empty_columns = []
|
||||
|
||||
for column in range(size - 1, -1, -1):
|
||||
if all(matrix_g[row][column] == "-" for row in range(size)):
|
||||
empty_columns.append(column)
|
||||
|
||||
for column in empty_columns:
|
||||
for col in range(column + 1, size):
|
||||
for row in range(size):
|
||||
matrix_g[row][col - 1] = matrix_g[row][col]
|
||||
for row in range(size):
|
||||
matrix_g[row][-1] = "-"
|
||||
|
||||
return matrix_g
|
||||
|
||||
|
||||
def play(
|
||||
matrix_g: list[list[str]], pos_x: int, pos_y: int, size: int
|
||||
) -> tuple[list[list[str]], int]:
|
||||
"""
|
||||
Processes a single move, updating the matrix and calculating the score.
|
||||
|
||||
>>> play([['R', 'G'], ['R', 'G']], 0, 0, 2)
|
||||
([['G', '-'], ['G', '-']], 3)
|
||||
"""
|
||||
|
||||
same_colors = find_repeat(matrix_g, pos_x, pos_y, size)
|
||||
|
||||
if len(same_colors) != 0:
|
||||
for pos in same_colors:
|
||||
matrix_g[pos[0]][pos[1]] = "-"
|
||||
for column in range(size):
|
||||
matrix_g = move_x(matrix_g, column, size)
|
||||
|
||||
matrix_g = move_y(matrix_g, size)
|
||||
|
||||
return (matrix_g, increment_score(len(same_colors)))
|
||||
|
||||
|
||||
def process_game(size: int, matrix: list[str], moves: list[tuple[int, int]]) -> int:
|
||||
"""Processes the game logic for the given matrix and moves.
|
||||
|
||||
Args:
|
||||
size (int): Size of the game board.
|
||||
matrix (List[str]): Initial game matrix.
|
||||
moves (List[Tuple[int, int]]): List of moves as (x, y) coordinates.
|
||||
|
||||
Returns:
|
||||
int: The total score obtained.
|
||||
>>> process_game(3, ['aaa', 'bbb', 'ccc'], [(0, 0)])
|
||||
6
|
||||
"""
|
||||
|
||||
game_matrix = [list(row) for row in matrix]
|
||||
total_score = 0
|
||||
|
||||
for move in moves:
|
||||
pos_x, pos_y = move
|
||||
game_matrix, score = play(game_matrix, pos_x, pos_y, size)
|
||||
total_score += score
|
||||
|
||||
return total_score
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod(verbose=True)
|
||||
try:
|
||||
size = int(input("Enter the size of the matrix: "))
|
||||
validate_matrix_size(size)
|
||||
print(f"Enter the {size} rows of the matrix:")
|
||||
matrix = [input(f"Row {i+1}: ") for i in range(size)]
|
||||
validate_matrix_content(matrix, size)
|
||||
moves_input = input("Enter the moves (e.g., '0 0, 1 1'): ")
|
||||
moves = parse_moves(moves_input)
|
||||
validate_moves(moves, size)
|
||||
score = process_game(size, matrix, moves)
|
||||
print(f"Total score: {score}")
|
||||
except ValueError as e:
|
||||
print(f"{e}")
|
Loading…
Reference in New Issue
Block a user