NEW ACTIVITIES: activity46-game-theory-python.yaml - Game theory implementation in Python - Representing games with dictionaries - Payoff matrix as dict with tuple keys - Query functions and game simulation - One-shot and repeated games - Tit-for-Tat strategy implementation - Function composition and abstraction activity47-game-theory-c.yaml - Game theory implementation in C - Defining Payoff struct for outcomes - 2D arrays for payoff matrices - Memory-efficient game representation - Strategy lookup functions - Enum for self-documenting code - Pointer and struct fundamentals Both activities: - Teach programming through game theory concepts - Follow pedagogical best practice (concepts first, code examples in feedback) - Validate with zero errors/warnings - Progressive difficulty (structures → functions → simulation) - Real-world application of abstract concepts - Engage students with strategic thinking + coding
528 lines
20 KiB
YAML
528 lines
20 KiB
YAML
default_max_attempts_per_step: 3
|
|
classifier_model: "MODEL_1"
|
|
feedback_model: "MODEL_1"
|
|
tokens_for_ai_rubric: |
|
|
Evaluate the student's ability to implement game theory concepts in C.
|
|
|
|
Consider:
|
|
- Correct C syntax
|
|
- Proper use of structs and pointers
|
|
- Memory management awareness
|
|
- Understanding of game theory concepts
|
|
- Code structure and organization
|
|
|
|
sections:
|
|
- section_id: introduction
|
|
title: Programming Game Theory in C
|
|
steps:
|
|
- step_id: welcome
|
|
title: Systems Programming Meets Strategy
|
|
content_blocks:
|
|
- "# Game Theory Programming with C ⚙️🎮"
|
|
- ""
|
|
- "**Learn C by implementing game theory!**"
|
|
- ""
|
|
- "You'll learn to:"
|
|
- "✓ Define game structures with structs"
|
|
- "✓ Use 2D arrays for payoff matrices"
|
|
- "✓ Work with pointers and memory"
|
|
- "✓ Implement strategy functions"
|
|
- "✓ Build game simulators in C"
|
|
- ""
|
|
- "**Prerequisites:**"
|
|
- "- Basic C knowledge (variables, functions, arrays)"
|
|
- "- Understanding of basic game theory concepts"
|
|
- ""
|
|
- "**Why C for game theory:**"
|
|
- "- Performance for large simulations"
|
|
- "- Memory efficiency"
|
|
- "- Understanding low-level implementation"
|
|
- "- Foundation for understanding algorithms"
|
|
question: Ready to implement game theory in C?
|
|
tokens_for_ai: Accept positive as 'ready', language preference as 'set_language', else 'off_topic'
|
|
buckets: [ready, set_language, off_topic]
|
|
transitions:
|
|
ready:
|
|
next_section_and_step: structures:step_1
|
|
set_language:
|
|
metadata_add: {language: "the-users-response"}
|
|
counts_as_attempt: false
|
|
next_section_and_step: introduction:welcome
|
|
off_topic:
|
|
counts_as_attempt: false
|
|
next_section_and_step: introduction:welcome
|
|
|
|
- section_id: structures
|
|
title: Defining Game Structures
|
|
steps:
|
|
- step_id: step_1
|
|
title: Payoff Structure
|
|
content_blocks:
|
|
- "## Representing Payoffs in C 📐"
|
|
- ""
|
|
- "**The challenge:**"
|
|
- "How do we represent a payoff (two player outcomes) in C?"
|
|
- ""
|
|
- "**Conceptual requirement:**"
|
|
- "Each outcome has TWO values:"
|
|
- "- Player 1's payoff"
|
|
- "- Player 2's payoff"
|
|
- ""
|
|
- "**C solution: struct**"
|
|
- "A struct groups related data together"
|
|
- ""
|
|
- "**What your struct needs:**"
|
|
- "- A name (like 'Payoff' or 'Outcome')"
|
|
- "- Two integer fields for the two payoffs"
|
|
- ""
|
|
- "**Struct syntax reminder:**"
|
|
- "```"
|
|
- "struct StructName {"
|
|
- " type field1;"
|
|
- " type field2;"
|
|
- "};"
|
|
- "```"
|
|
question: "Define a C struct called 'Payoff' that contains two integer fields: 'player1' and 'player2' for storing each player's payoff."
|
|
tokens_for_ai: |
|
|
Looking for struct definition with:
|
|
- Name: Payoff (or similar like Outcome, GameResult)
|
|
- Two int fields for the two player payoffs
|
|
|
|
Correct examples:
|
|
struct Payoff {
|
|
int player1;
|
|
int player2;
|
|
};
|
|
|
|
or
|
|
|
|
typedef struct {
|
|
int p1;
|
|
int p2;
|
|
} Payoff;
|
|
|
|
Categorize as:
|
|
- correct: Valid struct with two int fields
|
|
- correct_concept: Right idea, minor syntax
|
|
- missing_fields: Struct but wrong/missing fields
|
|
- no_struct: Doesn't use struct
|
|
- confused: Wrong approach
|
|
- set_language: Language preference
|
|
- off_topic: Unrelated
|
|
feedback_tokens_for_ai: |
|
|
If correct:
|
|
- Perfect struct definition!
|
|
- Your struct groups the two payoffs together.
|
|
- Now you can create: struct Payoff outcome;
|
|
- Access: outcome.player1 = -1; outcome.player2 = -1;
|
|
|
|
If correct concept:
|
|
- Right idea! Small syntax adjustment:
|
|
- Show corrected version.
|
|
- Explain the fix.
|
|
|
|
If missing fields:
|
|
- Remember: need TWO integer fields
|
|
- One for player1's payoff
|
|
- One for player2's payoff
|
|
|
|
If no struct:
|
|
- C structs group related data!
|
|
- Show example struct format.
|
|
buckets: [correct, correct_concept, missing_fields, no_struct, confused, set_language, off_topic]
|
|
transitions:
|
|
correct:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Excellent struct definition!
|
|
Your Payoff struct elegantly groups both players' outcomes.
|
|
Usage: struct Payoff p = {-1, -2}; or p.player1 = 0;
|
|
This is the foundation for representing game outcomes!
|
|
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
|
|
next_section_and_step: structures:step_2
|
|
correct_concept:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Great concept! Minor syntax refinement:
|
|
Show corrected struct.
|
|
Explain the adjustment made.
|
|
metadata_add: {score: "n+1"}
|
|
next_section_and_step: structures:step_2
|
|
missing_fields:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Need two int fields!
|
|
|
|
struct Payoff {
|
|
int player1;
|
|
int player2;
|
|
};
|
|
|
|
This stores both players' payoffs together.
|
|
next_section_and_step: structures:step_1
|
|
no_struct:
|
|
content_blocks:
|
|
- "Use a struct to group the two payoffs:"
|
|
- "struct Payoff { ... };"
|
|
- "Include two int fields inside the braces"
|
|
next_section_and_step: structures:step_1
|
|
confused:
|
|
content_blocks:
|
|
- "Define a struct with:"
|
|
- "- Name: Payoff"
|
|
- "- Two int fields (one for each player's payoff)"
|
|
- "Don't forget the semicolon at the end!"
|
|
next_section_and_step: structures:step_1
|
|
set_language:
|
|
metadata_add: {language: "the-users-response"}
|
|
counts_as_attempt: false
|
|
next_section_and_step: structures:step_1
|
|
off_topic:
|
|
next_section_and_step: structures:step_1
|
|
|
|
- step_id: step_2
|
|
title: Payoff Matrix with 2D Array
|
|
content_blocks:
|
|
- "## 2D Array for Game Matrix 🎯"
|
|
- ""
|
|
- "**Representing a 2x2 game:**"
|
|
- ""
|
|
- "**Prisoner's Dilemma has:**"
|
|
- "- 2 strategies per player: cooperate (0) or defect (1)"
|
|
- "- 4 possible outcomes: (0,0), (0,1), (1,0), (1,1)"
|
|
- ""
|
|
- "**Perfect for a 2D array!**"
|
|
- ""
|
|
- "**Array structure:**"
|
|
- "- First index: player 1's strategy (0 or 1)"
|
|
- "- Second index: player 2's strategy (0 or 1)"
|
|
- "- Value: Payoff struct with both payoffs"
|
|
- ""
|
|
- "**Conceptual mapping:**"
|
|
- "```"
|
|
- "matrix[0][0] = both cooperate"
|
|
- "matrix[0][1] = p1 cooperates, p2 defects"
|
|
- "matrix[1][0] = p1 defects, p2 cooperates"
|
|
- "matrix[1][1] = both defect"
|
|
- "```"
|
|
- ""
|
|
- "**Array declaration concept:**"
|
|
- "You declare a 2D array of your Payoff struct"
|
|
- "Then initialize it with the four outcomes"
|
|
question: "Declare and initialize a 2D array called 'prisoners_dilemma' of Payoff structs representing the Prisoner's Dilemma game. Use indices 0=cooperate, 1=defect. Payoffs: both cooperate (-1,-1), both defect (-2,-2), one defects (0,-3) or (-3,0)."
|
|
tokens_for_ai: |
|
|
Looking for 2D array declaration and initialization:
|
|
|
|
struct Payoff prisoners_dilemma[2][2] = {
|
|
{{-1, -1}, {-3, 0}}, // p1 cooperates
|
|
{{0, -3}, {-2, -2}} // p1 defects
|
|
};
|
|
|
|
Or similar valid initialization.
|
|
|
|
Categorize as:
|
|
- correct: Valid 2D array with proper payoffs
|
|
- correct_structure: Right format, payoff errors
|
|
- wrong_dimensions: Not 2x2
|
|
- syntax_errors: C syntax issues
|
|
- confused: Wrong approach
|
|
- set_language: Language preference
|
|
- off_topic: Unrelated
|
|
feedback_tokens_for_ai: |
|
|
If correct:
|
|
- Perfect 2D array implementation!
|
|
- prisoners_dilemma[0][0] = both cooperate = {-1,-1}
|
|
- prisoners_dilemma[1][1] = both defect = {-2,-2}
|
|
- prisoners_dilemma[0][1] = p1 cooperate, p2 defect = {-3,0}
|
|
- prisoners_dilemma[1][0] = p1 defect, p2 cooperate = {0,-3}
|
|
- Efficient memory layout for game representation!
|
|
|
|
If structure right:
|
|
- Great array structure! Payoff corrections:
|
|
- Show corrected initialization.
|
|
- Explain the Prisoner's Dilemma payoffs.
|
|
|
|
If wrong dimensions:
|
|
- Need 2x2 array (2 strategies per player)
|
|
- struct Payoff name[2][2] = {...};
|
|
|
|
If syntax errors:
|
|
- Show correct C array initialization syntax.
|
|
- Explain the nested braces structure.
|
|
buckets: [correct, correct_structure, wrong_dimensions, syntax_errors, confused, set_language, off_topic]
|
|
transitions:
|
|
correct:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Excellent array implementation!
|
|
Your 2D array efficiently represents the payoff matrix.
|
|
Access is simple: prisoners_dilemma[i][j]
|
|
Memory layout is contiguous and cache-friendly.
|
|
This is how game theory simulations optimize performance!
|
|
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
|
|
next_section_and_step: functions:step_1
|
|
correct_structure:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Great structure! Payoff corrections for Prisoner's Dilemma:
|
|
Show corrected initialization with explanations.
|
|
Explain why these specific payoffs create the dilemma.
|
|
metadata_add: {score: "n+1"}
|
|
next_section_and_step: functions:step_1
|
|
wrong_dimensions:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Need 2x2 for two-strategy game:
|
|
|
|
struct Payoff game[2][2] = {
|
|
{{-1,-1}, {-3,0}},
|
|
{{0,-3}, {-2,-2}}
|
|
};
|
|
next_section_and_step: structures:step_2
|
|
syntax_errors:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
C array initialization uses nested braces:
|
|
|
|
struct Payoff arr[2][2] = {
|
|
{row0_col0, row0_col1},
|
|
{row1_col0, row1_col1}
|
|
};
|
|
|
|
Each Payoff is {p1_payoff, p2_payoff}
|
|
next_section_and_step: structures:step_2
|
|
confused:
|
|
content_blocks:
|
|
- "Declare: struct Payoff prisoners_dilemma[2][2]"
|
|
- "Initialize with nested braces: {{...}, {...}}"
|
|
- "Four outcomes total (2x2 = 4 combinations)"
|
|
next_section_and_step: structures:step_2
|
|
set_language:
|
|
metadata_add: {language: "the-users-response"}
|
|
counts_as_attempt: false
|
|
next_section_and_step: structures:step_2
|
|
off_topic:
|
|
next_section_and_step: structures:step_2
|
|
|
|
- section_id: functions
|
|
title: Strategy Functions
|
|
steps:
|
|
- step_id: step_1
|
|
title: Lookup Function
|
|
content_blocks:
|
|
- "## Querying the Payoff Matrix 🔍"
|
|
- ""
|
|
- "**Create a function to get payoffs**"
|
|
- ""
|
|
- "**Function requirements:**"
|
|
- "- Name: `get_payoff`"
|
|
- "- Parameters: 2D array (pointer), two strategy indices"
|
|
- "- Returns: Payoff struct"
|
|
- ""
|
|
- "**C function concepts:**"
|
|
- "- Pass 2D array as pointer"
|
|
- "- Access with array indexing"
|
|
- "- Return struct by value"
|
|
- ""
|
|
- "**What it does:**"
|
|
- "Takes strategies (0 or 1 for each player)"
|
|
- "Returns the corresponding Payoff from the matrix"
|
|
question: "Write a C function called 'get_payoff' that takes a 2D Payoff array (as pointer) and two integer strategy indices, then returns the Payoff struct for that strategy combination."
|
|
tokens_for_ai: |
|
|
Acceptable function signatures:
|
|
- struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2)
|
|
- struct Payoff get_payoff(struct Payoff (*matrix)[2], int s1, int s2)
|
|
|
|
Function body should:
|
|
- Return matrix[s1][s2];
|
|
|
|
Categorize as:
|
|
- correct: Valid function with proper syntax
|
|
- correct_logic: Right idea, minor syntax
|
|
- wrong_return: Doesn't return Payoff struct
|
|
- pointer_confusion: Struggles with array parameter
|
|
- confused: Wrong approach
|
|
- set_language: Language preference
|
|
- off_topic: Unrelated
|
|
feedback_tokens_for_ai: |
|
|
If correct:
|
|
- Perfect function!
|
|
- Your function cleanly accesses the 2D array.
|
|
- Returning struct by value is simple and safe here.
|
|
- Usage: struct Payoff p = get_payoff(game, 0, 1);
|
|
|
|
If correct logic:
|
|
- Great logic! Minor syntax refinement:
|
|
- Show corrected version.
|
|
- Explain the C-specific details.
|
|
|
|
If wrong return:
|
|
- Function should return struct Payoff
|
|
- return matrix[s1][s2]; gives you the Payoff struct.
|
|
|
|
If pointer confusion:
|
|
- For small 2D arrays, can pass as: struct Payoff matrix[2][2]
|
|
- Or use pointer: struct Payoff (*matrix)[2]
|
|
- Show working example.
|
|
buckets: [correct, correct_logic, wrong_return, pointer_confusion, confused, set_language, off_topic]
|
|
transitions:
|
|
correct:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Excellent function implementation!
|
|
Your get_payoff function cleanly retrieves outcomes.
|
|
C's struct return makes this straightforward.
|
|
You've encapsulated the lookup logic perfectly!
|
|
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
|
|
next_section_and_step: simulation:step_1
|
|
correct_logic:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Great logic! Small C syntax refinement:
|
|
Show polished version.
|
|
Explain the specific C conventions used.
|
|
metadata_add: {score: "n+1"}
|
|
next_section_and_step: simulation:step_1
|
|
wrong_return:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Return type should be struct Payoff:
|
|
|
|
struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2) {
|
|
return matrix[s1][s2];
|
|
}
|
|
next_section_and_step: functions:step_1
|
|
pointer_confusion:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
For 2D array parameter, simple approach:
|
|
|
|
struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2) {
|
|
return matrix[s1][s2];
|
|
}
|
|
|
|
C automatically handles the array as pointer.
|
|
next_section_and_step: functions:step_1
|
|
confused:
|
|
content_blocks:
|
|
- "Function signature: struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2)"
|
|
- "Function body: return matrix[s1][s2];"
|
|
- "This returns the Payoff at position [s1][s2]"
|
|
next_section_and_step: functions:step_1
|
|
set_language:
|
|
metadata_add: {language: "the-users-response"}
|
|
counts_as_attempt: false
|
|
next_section_and_step: functions:step_1
|
|
off_topic:
|
|
next_section_and_step: functions:step_1
|
|
|
|
- section_id: simulation
|
|
title: Game Simulation
|
|
steps:
|
|
- step_id: step_1
|
|
title: Strategy Enumeration
|
|
content_blocks:
|
|
- "## Defining Strategies with Enum 🎲"
|
|
- ""
|
|
- "**Making code readable:**"
|
|
- "Instead of 0 and 1, use named constants!"
|
|
- ""
|
|
- "**C enum for strategies:**"
|
|
- "Enums give names to integer values"
|
|
- ""
|
|
- "**What you need:**"
|
|
- "- Enum name: Strategy (or similar)"
|
|
- "- Two values: COOPERATE = 0, DEFECT = 1"
|
|
- ""
|
|
- "**Why enums improve code:**"
|
|
- "- get_payoff(game, COOPERATE, DEFECT) is clearer"
|
|
- "- Better than get_payoff(game, 0, 1)"
|
|
- "- Self-documenting code"
|
|
- "- Type safety (to some degree)"
|
|
question: "Define a C enum called 'Strategy' with two values: COOPERATE (equals 0) and DEFECT (equals 1)."
|
|
tokens_for_ai: |
|
|
Looking for enum definition:
|
|
|
|
enum Strategy {
|
|
COOPERATE = 0,
|
|
DEFECT = 1
|
|
};
|
|
|
|
Or:
|
|
typedef enum {
|
|
COOPERATE = 0,
|
|
DEFECT = 1
|
|
} Strategy;
|
|
|
|
Categorize as:
|
|
- correct: Valid enum with both values
|
|
- correct_concept: Right idea, minor syntax
|
|
- missing_values: Enum but wrong values
|
|
- no_enum: Doesn't use enum
|
|
- confused: Wrong approach
|
|
- set_language: Language preference
|
|
- off_topic: Unrelated
|
|
feedback_tokens_for_ai: |
|
|
If correct:
|
|
- Perfect enum definition!
|
|
- Now you can write: enum Strategy s = COOPERATE;
|
|
- Much more readable than: int s = 0;
|
|
- Self-documenting code is maintainable code!
|
|
|
|
If correct concept:
|
|
- Great use of enum! Small refinement:
|
|
- Show corrected version.
|
|
|
|
If missing values:
|
|
- Need both COOPERATE = 0 and DEFECT = 1
|
|
- Show correct enum.
|
|
|
|
If no enum:
|
|
- C enums create named integer constants:
|
|
- Show enum syntax.
|
|
buckets: [correct, correct_concept, missing_values, no_enum, confused, set_language, off_topic]
|
|
transitions:
|
|
correct:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Excellent enum!
|
|
Your code is now self-documenting.
|
|
COOPERATE and DEFECT are much clearer than 0 and 1.
|
|
This is professional C code style!
|
|
You've mastered game theory implementation in C!
|
|
metadata_add: {score: "n+2", concepts_mastered: "n+1", activity_completed: "true"}
|
|
correct_concept:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Great enum concept! Small polish:
|
|
Show refined version.
|
|
You understand C enums well!
|
|
metadata_add: {score: "n+1", activity_completed: "true"}
|
|
missing_values:
|
|
ai_feedback:
|
|
tokens_for_ai: |
|
|
Need both strategies:
|
|
|
|
enum Strategy {
|
|
COOPERATE = 0,
|
|
DEFECT = 1
|
|
};
|
|
next_section_and_step: simulation:step_1
|
|
no_enum:
|
|
content_blocks:
|
|
- "Define enum with:"
|
|
- "enum Strategy { COOPERATE = 0, DEFECT = 1 };"
|
|
- "This creates named constants"
|
|
next_section_and_step: simulation:step_1
|
|
confused:
|
|
content_blocks:
|
|
- "Enum syntax: enum Name { VALUE1 = 0, VALUE2 = 1 };"
|
|
- "Creates named integer constants"
|
|
- "Don't forget the semicolon!"
|
|
next_section_and_step: simulation:step_1
|
|
set_language:
|
|
metadata_add: {language: "the-users-response"}
|
|
counts_as_attempt: false
|
|
next_section_and_step: simulation:step_1
|
|
off_topic:
|
|
metadata_add: {activity_completed: "true"}
|