Message
Message
import random
import sys
import os
import math
import numpy as np # Added NumPy library for efficient computations
from pygame.locals import *
# Initialize Pygame
pygame.init()
# Screen dimensions
WIDTH, HEIGHT = 1024, 768
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Advanced N-Back Game with Enhanced 3D Rendering and
NumPy")
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# Fonts
pygame.font.init()
FONT = pygame.font.SysFont("Verdana", 20)
BIG_FONT = pygame.font.SysFont("Verdana", 36)
TITLE_FONT = pygame.font.SysFont("Verdana", 48)
# Timing
STIMULUS_DURATION = 1000 # milliseconds
INTER_STIMULUS_INTERVAL = 500 # milliseconds
BREAK_DURATION = 10000 # milliseconds (10 seconds break)
TRIALS_BEFORE_BREAK = 20 # Number of trials before a break
# Game modes
MODES = ["Visual N-Back", "Auditory N-Back", "Shape N-Back", "Dual N-Back"]
# Themes
THEMES = {
"Default": {
"BACKGROUND": (30, 30, 30),
"GRID_LINES": (200, 200, 200),
"HIGHLIGHT": (0, 120, 215),
"SHAPE": (173, 216, 230),
"TEXT": WHITE,
"BUTTON": (255, 165, 0),
"BUTTON_HOVER": (255, 215, 0)
},
"Galaxy": {
"BACKGROUND": (10, 10, 30),
"GRID_LINES": (70, 70, 120),
"HIGHLIGHT": (138, 43, 226),
"SHAPE": (75, 0, 130),
"TEXT": WHITE,
"BUTTON": (72, 61, 139),
"BUTTON_HOVER": (123, 104, 238)
},
# Additional themes can be added here
}
class NBackGame:
def __init__(self):
# Player Information
self.player_name = "Player"
self.ask_player_name()
self.init_gui()
# For 3D rendering
self.fov = 75 # Field of view
self.near_plane = 0.1
self.far_plane = 1000
self.settings_options = [
{"label": "N-Back Level", "value": self.N_LEVEL},
{"label": "Stimulus Duration", "value": f"{STIMULUS_DURATION} ms"},
{"label": "Game Mode", "value": self.mode},
{"label": "3D Mode", "value": "On" if self.is_3d else "Off"},
{"label": "Camera Distance", "value": f"{-self.camera_pos[2]}"},
{"label": "Shapes", "value": "On" if self.shapes_enabled else "Off"},
{"label": "Theme", "value": self.theme},
{"label": "Back", "value": ""}
]
self.update_instructions()
def update_instructions(self):
self.instructions_text = [
f"Welcome, {self.player_name}, to the {self.mode}!",
"In this game, you'll be presented with stimuli.",
f"Your task is to press 'S' if the current stimulus matches the one",
f"from N steps earlier in the sequence (N = {self.N_LEVEL}).",
"Press 'Enter' to go back to the main menu."
]
if self.mode in ["Auditory N-Back", "Dual N-Back"]:
self.instructions_text.insert(4, "Press 'A' if the auditory stimulus
matches.")
if self.shapes_enabled:
self.instructions_text.insert(5, "Press 'D' if the shape stimulus
matches.")
cube_faces = []
# Build cubes for each grid position
for x in range(self.GRID_SIZE):
for y in range(self.GRID_SIZE):
for z in range(self.GRID_SIZE):
cube = self.create_cube(np.array([x, y, z]) -
self.GRID_SIZE / 2)
transformed_faces = []
for face in cube:
transformed_face = []
for vertex in face:
v = self.apply_transformations(vertex,
camera_matrix, projection_matrix)
if v is not None:
transformed_face.append(v)
if len(transformed_face) == 4:
# Calculate average depth for sorting
avg_depth = sum(v[2] for v in transformed_face) /
len(transformed_face)
transformed_faces.append((transformed_face,
avg_depth))
cube_faces.extend(transformed_faces)
# Draw faces
for face, _ in cube_faces:
pygame.draw.polygon(SCREEN, self.colors["GRID_LINES"], [(v[0],
v[1]) for v in face], 1)
else:
# Draw 2D grid
for x in range(self.GRID_SIZE + 1):
pygame.draw.line(SCREEN, self.colors["GRID_LINES"], (x * 40, 0), (x
* 40, self.GRID_SIZE * 40), 1)
pygame.draw.line(SCREEN, self.colors["GRID_LINES"], (0, x * 40),
(self.GRID_SIZE * 40, x * 40), 1)
return np.array([
[xaxis[0], yaxis[0], zaxis[0], 0],
[xaxis[1], yaxis[1], zaxis[1], 0],
[xaxis[2], yaxis[2], zaxis[2], 0],
[tx, ty, tz, 1]
])
if self.user_position_match:
self.attempted += 1
if position_match:
self.score += 1
self.correct += 1
else:
self.score -= 1
else:
if position_match:
# Missed a match
self.score -= 1
if self.user_sound_match:
self.attempted += 1
if sound_match:
self.score += 1
self.correct += 1
else:
self.score -= 1
else:
if sound_match:
# Missed a match
self.score -= 1
# Show instructions
def show_instructions(self):
self.transition_to("instructions")
# Show settings
def show_settings(self):
self.transition_to("settings")
# Show scoreboard
def show_scoreboard(self):
self.transition_to("scoreboard")
while self.running:
if self.transitioning:
self.transition_alpha -= 5
if self.transition_alpha <= 0:
self.transition_alpha = 0
self.transitioning = False
if self.state == "menu":
self.display_menu()
self.handle_menu_events()
elif self.state == "instructions":
self.display_instructions()
self.handle_instructions_events()
elif self.state == "settings":
self.display_settings()
self.handle_settings_events()
elif self.state == "scoreboard":
self.display_scoreboard()
elif self.state == "game":
SCREEN.fill(self.colors["BACKGROUND"])
self.draw_grid()
self.display_score()
self.display_statistics()
current_time = pygame.time.get_ticks()
if self.in_break:
if current_time >= self.break_end_time:
self.in_break = False
self.next_stimulus_time = current_time +
INTER_STIMULUS_INTERVAL
else:
# Display "Break" during the break period
break_surface = BIG_FONT.render("Break", True,
self.colors["TEXT"])
SCREEN.blit(break_surface, (WIDTH // 2 -
break_surface.get_width() // 2, HEIGHT // 2 - break_surface.get_height() // 2))
else:
if current_time >= self.next_stimulus_time:
# Check if we need to initiate a break
if self.trials_since_break >= TRIALS_BEFORE_BREAK:
self.in_break = True
self.break_end_time = current_time + BREAK_DURATION
self.trials_since_break = 0
else:
# Get new stimulus
stimulus = self.get_random_stimulus()
self.sequence.append(stimulus)
self.total_trials += 1
self.trials_since_break += 1
self.handle_game_events()
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
class Button:
def __init__(self, text, pos, callback):
self.text = text
self.pos = pos
self.callback = callback
self.rect = pygame.Rect(0, 0, 250, 50)
self.rect.center = pos
self.hovered = False
if __name__ == "__main__":
game = NBackGame()
game.main_loop()