Add Mice! game and associated tools

- Created gameinfo.xml for the Mice! game, detailing its description, release date, developer, and genre.
- Added mice.sh script to activate the conda environment and run the game.
- Implemented colorize_assets.py as a placeholder for future asset colorization functionality.
- Developed convert_audio.py to convert audio files to 8-bit unsigned format at 22100 Hz.
- Introduced maze.py for generating mazes using Depth First Search (DFS) with a graphical interface.
- Created resize_assets.py to resize PNG assets to 18x18 pixels and center them on a 20x20 canvas.
This commit is contained in:
2025-08-18 00:20:40 +02:00
parent 8a32aad877
commit 3bd2d9269f
10 changed files with 33 additions and 11 deletions
View File
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
"""
Audio conversion script to convert audio files to u8 22100 Hz format
"""
from pydub import AudioSegment
import os
import sys
import argparse
def convert_audio(input_path, output_path=None):
"""Convert audio file to u8 format at 22100 Hz"""
# Generate output path if not provided
if output_path is None:
base_name = os.path.splitext(input_path)[0]
output_path = f"{base_name}_converted.wav"
if not os.path.exists(input_path):
print(f"Error: {input_path} not found!")
return
try:
# Load the audio file
print(f"Loading {input_path}...")
audio = AudioSegment.from_wav(input_path)
# Print current format info
print(f"Original format:")
print(f" Sample rate: {audio.frame_rate} Hz")
print(f" Channels: {audio.channels}")
print(f" Sample width: {audio.sample_width} bytes ({audio.sample_width * 8} bits)")
print(f" Duration: {len(audio)} ms")
# Convert to mono if stereo
if audio.channels > 1:
print("Converting to mono...")
audio = audio.set_channels(1)
# Convert to 22100 Hz sample rate
print("Converting sample rate to 22100 Hz...")
audio = audio.set_frame_rate(22100)
# Convert to 8-bit unsigned (u8)
print("Converting to 8-bit unsigned format...")
audio = audio.set_sample_width(1) # 1 byte = 8 bits
# Export the converted audio
print(f"Saving to {output_path}...")
audio.export(output_path, format="wav")
# Print new format info
converted_audio = AudioSegment.from_wav(output_path)
print(f"\nConverted format:")
print(f" Sample rate: {converted_audio.frame_rate} Hz")
print(f" Channels: {converted_audio.channels}")
print(f" Sample width: {converted_audio.sample_width} bytes ({converted_audio.sample_width * 8} bits)")
print(f" Duration: {len(converted_audio)} ms")
print(f"\nConversion complete! Output saved as: {output_path}")
# Optionally replace the original file
replace = input("\nReplace original mine.wav with converted version? (y/n): ").lower()
if replace == 'y':
import shutil
# Backup original
backup_path = "sound/mine_original.wav"
shutil.copy2(input_path, backup_path)
print(f"Original file backed up as: {backup_path}")
# Replace original
shutil.copy2(output_path, input_path)
os.remove(output_path)
print(f"Original file replaced with converted version.")
except Exception as e:
print(f"Error during conversion: {e}")
def main():
"""Main function to handle command line arguments"""
parser = argparse.ArgumentParser(description='Convert audio files to u8 22100 Hz format')
parser.add_argument('input_file', help='Input audio file path')
parser.add_argument('-o', '--output', help='Output file path (optional)')
args = parser.parse_args()
convert_audio(args.input_file, args.output)
if __name__ == "__main__":
main()
+108
View File
@@ -0,0 +1,108 @@
# DFS: Depth First Search
import random
import tkinter as tk
import json
import time
class MazeGenerator:
def __init__(self, width=10, height=10):
self.width = width * 2 + 1 # Considera le pareti nel calcolo della larghezza
self.height = height * 2 + 1 # Considera le pareti nel calcolo dell'altezza
self.generate_maze()
self.window = tk.Tk()
self.window.title("Maze")
self.canvas = tk.Canvas(self.window, width=self.width*10, height=self.height*10)
self.canvas.pack()
self.arrival_point = (self.width - 2, self.height - 2) # Aggiorna il punto di arrivo
self.backtrack = []
def generate_maze(self):
# Inizializza il labirinto con muri (True)
self.maze = [[True for _ in range(self.width)] for _ in range(self.height)]
# Definisci le direzioni (N, S, E, W)
self.directions = [(-2, 0), (2, 0), (0, -2), (0, 2)]
# Punto di partenza
start_x, start_y = (1, 1)
self.maze[start_y][start_x] = False
self.stack = [(start_x, start_y)]
def stack_iteration(self):
if not self.stack: # Check if the stack is empty
return
current_x, current_y = self.stack[-1]
# Function to get the unvisited neighbors
def get_unvisited_neighbors(x, y):
time.sleep(0.005)
neighbors = []
if not (self.arrival_point == (x,y)):
for dx, dy in self.directions:
nx, ny = x + dx, y + dy
if 1 <= nx < self.width - 1 and 1 <= ny < self.height - 1 and self.maze[ny][nx]:
neighbors.append((nx, ny))
return neighbors
neighbors = get_unvisited_neighbors(current_x, current_y)
if neighbors:
# Choose a random unvisited neighbor
chosen_x, chosen_y = random.choice(neighbors)
# Remove the wall between the current cell and the chosen cell
self.maze[(current_y + chosen_y) // 2][(current_x + chosen_x) // 2] = False
# Mark the chosen cell as visited
self.maze[chosen_y][chosen_x] = False
# Push the chosen cell to the stack
self.stack.append((chosen_x, chosen_y))
else:
# Backtrack if no unvisited neighbors are found
self.backtrack.append(self.stack.pop())
def update_maze(self):
self.stack_iteration()
self.draw_maze()
if self.stack: # Continue updating only if there are cells left to visit
self.window.after(10, self.update_maze)
else:
self.add_random_passages()
self.draw_maze()
with open('maze.json', 'w') as json_file:
json.dump(self.maze, json_file)
def add_random_passages(self):
# Aggiungi passaggi casuali tra i corridoi
for _ in range(30):
x = random.randrange(1, self.width - 1, 2)
y = random.randrange(1, self.height - 1, 2)
print(x, y)
self.maze[y][x] = False
def draw_maze(self):
self.canvas.delete("all")
for i in range(self.height):
for j in range(self.width):
color = "black" if self.maze[i][j] else "white"
# if (i, j) in self.backtrack:
# color="yellow"
if (i, j) == self.arrival_point:
color = "green" # Color the arrival point green
elif (i, j) == (1 ,1):
color = "red" # Color the arrival point green
elif self.stack and (j, i) == self.stack[-1]:
color = "blue" # Color the current position blue
self.canvas.create_rectangle(j*10, i*10, (j+1)*10, (i+1)*10, fill=color)
def run(self):
self.update_maze()
self.window.mainloop()
# Crea e avvia il generatore di labirinti
generator = MazeGenerator(15, 8)
generator.run()
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""
Script to resize PNG asset files to 18x18 pixels and center them on a 20x20 canvas.
Saves the result back to the same file.
"""
import os
import glob
from PIL import Image, ImageOps
import argparse
def resize_and_center_image(image_path, target_size=(18, 18), canvas_size=(20, 20)):
"""
Resize an image to target_size and center it on a canvas of canvas_size.
Args:
image_path (str): Path to the image file
target_size (tuple): Size to resize the image to (width, height)
canvas_size (tuple): Size of the final canvas (width, height)
"""
try:
# Open the image
with Image.open(image_path) as img:
# Convert to RGBA to handle transparency
img = img.convert("RGBA")
# Resize the image to target size using high-quality resampling
resized_img = img.resize(target_size, Image.Resampling.LANCZOS)
# Create a new transparent canvas
canvas = Image.new("RGBA", canvas_size, (0, 0, 0, 0))
# Calculate position to center the resized image
x_offset = (canvas_size[0] - target_size[0]) // 2
y_offset = (canvas_size[1] - target_size[1]) // 2
# Paste the resized image onto the canvas
canvas.paste(resized_img, (x_offset, y_offset), resized_img)
# Save back to the same file
canvas.save(image_path, "PNG", optimize=True)
print(f"✓ Processed: {os.path.basename(image_path)}")
except Exception as e:
print(f"✗ Error processing {image_path}: {str(e)}")
def process_directory(directory_path, file_pattern="*.png"):
"""
Process all PNG files in a directory.
Args:
directory_path (str): Path to the directory containing PNG files
file_pattern (str): Pattern to match files (default: "*.png")
"""
if not os.path.exists(directory_path):
print(f"Error: Directory '{directory_path}' does not exist.")
return
# Find all PNG files matching the pattern
search_pattern = os.path.join(directory_path, file_pattern)
png_files = glob.glob(search_pattern)
if not png_files:
print(f"No PNG files found in '{directory_path}' matching pattern '{file_pattern}'")
return
print(f"Found {len(png_files)} PNG files to process...")
# Process each file
for png_file in png_files:
resize_and_center_image(png_file)
print(f"\nCompleted processing {len(png_files)} files.")
def process_single_file(file_path):
"""
Process a single PNG file.
Args:
file_path (str): Path to the PNG file
"""
if not os.path.exists(file_path):
print(f"Error: File '{file_path}' does not exist.")
return
if not file_path.lower().endswith('.png'):
print(f"Error: File '{file_path}' is not a PNG file.")
return
print(f"Processing single file: {os.path.basename(file_path)}")
resize_and_center_image(file_path)
print("Processing complete.")
def main():
parser = argparse.ArgumentParser(description="Resize PNG assets to 18x18px and center on 20x20px canvas")
parser.add_argument("path", help="Path to PNG file or directory containing PNG files")
parser.add_argument("--pattern", default="*.png", help="File pattern to match (default: *.png)")
args = parser.parse_args()
if os.path.isfile(args.path):
process_single_file(args.path)
elif os.path.isdir(args.path):
process_directory(args.path, args.pattern)
else:
print(f"Error: '{args.path}' is not a valid file or directory.")
if __name__ == "__main__":
# If run without arguments, process the assets/Rat directory by default
import sys
if len(sys.argv) == 1:
# Default to processing the assets/Rat directory
script_dir = os.path.dirname(os.path.abspath(__file__))
assets_dir = os.path.join(script_dir, "assets", "Rat")
if os.path.exists(assets_dir):
print("No arguments provided. Processing assets/Rat directory by default...")
process_directory(assets_dir)
else:
print("assets/Rat directory not found. Please provide a path as argument.")
print("Usage: python resize_assets.py <path_to_file_or_directory>")
else:
main()