diff --git a/CLAUDE.md b/CLAUDE.md index f16a203..457db1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,4 +19,7 @@ ## Documentation - Update relevant documentation when making significant changes - Keep README files current with new features or setup changes -- Document any new environment variables or configuration options \ No newline at end of file +- Document any new environment variables or configuration options + +## Python/Matplotlib Best Practices +- Always add `matplotlib.use("Agg")` before importing matplotlib.pyplot to prevent runtime errors in headless environments \ No newline at end of file diff --git a/app.py b/app.py index 179c922..7400efb 100644 --- a/app.py +++ b/app.py @@ -1744,7 +1744,7 @@ def handle_activity_response(room_name, user_response, username): temp_metadata["user_response"] = user_response pre_result = execute_processing_script( temp_metadata, step["pre_script"] - ) + ) or {} # Update metadata with pre-script results for key, value in pre_result.get("metadata", {}).items(): activity_state.add_metadata(key, value) @@ -1990,7 +1990,7 @@ def handle_activity_response(room_name, user_response, username): print(f"DEBUG: Executing post-script") result = execute_processing_script( activity_state.dict_metadata, post_script - ) + ) or {} plot_image_base64 = result.pop("plot_image", None) diff --git a/research/activity24-math-plot.yaml b/research/activity24-math-plot.yaml index eb82c6c..0530be0 100644 --- a/research/activity24-math-plot.yaml +++ b/research/activity24-math-plot.yaml @@ -2,6 +2,8 @@ default_max_attempts_per_step: 3 # Common processing script for all plotting steps common_processing_script: &plotting_script | + import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot import numpy import io diff --git a/research/activity27-tic-tac-toe.yaml b/research/activity27-tic-tac-toe.yaml index 2d1f29c..5b8e9f8 100644 --- a/research/activity27-tic-tac-toe.yaml +++ b/research/activity27-tic-tac-toe.yaml @@ -59,6 +59,8 @@ sections: def plot_board(board, win_line=None): import io import base64 + import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(3, 3)) diff --git a/research/activity28-killer-squares.yaml b/research/activity28-killer-squares.yaml index 5830397..69c4fae 100644 --- a/research/activity28-killer-squares.yaml +++ b/research/activity28-killer-squares.yaml @@ -111,6 +111,8 @@ sections: If game_over = True, suggest: "Would you like to restart and play again, or would you prefer to exit?" processing_script: | import random + import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot as plt import io import base64 diff --git a/research/activity29-battleship.yaml b/research/activity29-battleship.yaml index 461110d..ac1c628 100644 --- a/research/activity29-battleship.yaml +++ b/research/activity29-battleship.yaml @@ -205,6 +205,8 @@ sections: processing_script: | import random + import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot as plt import io import base64 @@ -564,19 +566,20 @@ sections: max_prob = 0 candidates = [] for i in range(100): - x, y = i % 10, i // 10 - if probability_matrix[y][x] > max_prob: - max_prob = probability_matrix[y][x] - candidates = [i] - elif probability_matrix[y][x] == max_prob: - candidates.append(i) + if i not in ai_shots: # Exclude already-fired cells + x, y = i % 10, i // 10 + if probability_matrix[y][x] > max_prob: + max_prob = probability_matrix[y][x] + candidates = [i] + elif probability_matrix[y][x] == max_prob: + candidates.append(i) ai_shot = random.choice(candidates) elif ai_mode == "hunter": # Simple hunter mode logic if hits: # Target adjacent cells of the last hit last_hit = hits[-1] - hunt_targets = generate_hunt_targets(last_hit, ai_hits) + hunt_targets = generate_hunt_targets(last_hit, ai_shots) if hunt_targets: ai_shot = hunt_targets.pop(0) else: @@ -609,7 +612,7 @@ sections: return random.choice(available_positions) # Function to generate hunt targets around a hit - def generate_hunt_targets(hit_position, ai_hits): + def generate_hunt_targets(hit_position, ai_shots): potential_targets = [] row, col = divmod(hit_position, 10) @@ -626,10 +629,10 @@ sections: if col < 9: potential_targets.append(hit_position + 1) - # Filter out already hit positions + # Filter out already fired positions filtered_targets = [] for pos in potential_targets: - if pos not in ai_hits: + if pos not in ai_shots: filtered_targets.append(pos) return filtered_targets diff --git a/research/activity29-testship.yaml b/research/activity29-testship.yaml index b28b423..aacb207 100644 --- a/research/activity29-testship.yaml +++ b/research/activity29-testship.yaml @@ -183,6 +183,8 @@ sections: processing_script: | import random + import matplotlib + matplotlib.use("Agg") import matplotlib.pyplot as plt import io import base64 @@ -534,19 +536,20 @@ sections: max_prob = 0 candidates = [] for i in range(100): - x, y = i % 10, i // 10 - if probability_matrix[y][x] > max_prob: - max_prob = probability_matrix[y][x] - candidates = [i] - elif probability_matrix[y][x] == max_prob: - candidates.append(i) + if i not in ai_shots: # Exclude already-fired cells + x, y = i % 10, i // 10 + if probability_matrix[y][x] > max_prob: + max_prob = probability_matrix[y][x] + candidates = [i] + elif probability_matrix[y][x] == max_prob: + candidates.append(i) ai_shot = random.choice(candidates) elif ai_mode == "hunter": # Simple hunter mode logic if hits: # Target adjacent cells of the last hit last_hit = hits[-1] - hunt_targets = generate_hunt_targets(last_hit, ai_hits) + hunt_targets = generate_hunt_targets(last_hit, ai_shots) if hunt_targets: ai_shot = hunt_targets.pop(0) else: @@ -579,7 +582,7 @@ sections: return random.choice(available_positions) # Function to generate hunt targets around a hit - def generate_hunt_targets(hit_position, ai_hits): + def generate_hunt_targets(hit_position, ai_shots): potential_targets = [] row, col = divmod(hit_position, 10) @@ -596,10 +599,10 @@ sections: if col < 9: potential_targets.append(hit_position + 1) - # Filter out already hit positions + # Filter out already fired positions filtered_targets = [] for pos in potential_targets: - if pos not in ai_hits: + if pos not in ai_shots: filtered_targets.append(pos) return filtered_targets