Video Game Design and Coding

Week 11 packet

Student instructions, tasks, and checks. The answer key is not in this packet. Links stay as text. This page does not embed a clip or run a file.

# Week 11 — Puzzle logic that can be proved

## VGC-L051 — Turn a story condition into Boolean logic

**Objective:** Translate a rule with and, or and not.

**Time:** 55 minutes

### Instruction
A locked archive gate opens when the player has the key, the lever is on and the alarm is off. Those three facts are Booleans. C-PUZZLE expresses the rule with and and not. Parentheses clarify mixed and/or conditions. Write the rule in ordinary language first, then code it, then test it independently of the story interface. Avoid checking visible text such as “Key found” as if it were game state; text can be edited without changing possession.

### Worked example
A separate practice door might require badge OR helper_present. Test each Boolean combination on paper before using the function to show an Open button.

Scaffold C-PUZZLE — A testable gate rule
Setup: Create Node root GateLab and attach this script. The pure gate_open function does not read input or change a scene. A level can call it with its inventory and lever state. Assertions run on start. For the assignment write additional tests before changing the rule.
```gdscript
extends Node
func gate_open(has_key: bool, lever_on: bool, alarm_on: bool) -> bool:
    return has_key and lever_on and not alarm_on
func _ready() -> void:
    assert(gate_open(true, true, false))
    assert(not gate_open(false, true, false))
    assert(not gate_open(true, false, false))
    assert(not gate_open(true, true, true))
    print("Gate checks passed")
```

### Assignment
1. Write the gate rule in words and GDScript.
2. Test the four supplied combinations and one additional combination.

### Acceptance checks
- The gate opens only when all required conditions hold.
- The function returns a Boolean without changing inventory.

**Submit:** GateLab source and five-case result table.

**Question:** Does having the key alone open this gate?

**Support:** Use the C-PUZZLE pure function and a paper truth table before attaching conditions to UI. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Find a logically equivalent expression and verify all eight truth-table rows. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)

---

## VGC-L052 — Exhaust a small truth table

**Objective:** Prove a three-Boolean rule for all possible inputs.

**Time:** 55 minutes

### Instruction
Three independent Booleans have eight combinations because each doubles the number of possibilities. List them systematically rather than inventing random tests. Use false/false/false through true/true/true in a fixed order. For each row predict gate_open, then compare with the function. An exhaustive test is possible here because the input space is tiny; most large games need representative and boundary tests instead. A truth table can also reveal that a rule never opens or always opens by mistake.

### Worked example
A separate practice door might require badge OR helper_present. Test each Boolean combination on paper before using the function to show an Open button.

Scaffold C-PUZZLE — A testable gate rule
Setup: Create Node root GateLab and attach this script. The pure gate_open function does not read input or change a scene. A level can call it with its inventory and lever state. Assertions run on start. For the assignment write additional tests before changing the rule.
```gdscript
extends Node
func gate_open(has_key: bool, lever_on: bool, alarm_on: bool) -> bool:
    return has_key and lever_on and not alarm_on
func _ready() -> void:
    assert(gate_open(true, true, false))
    assert(not gate_open(false, true, false))
    assert(not gate_open(true, false, false))
    assert(not gate_open(true, true, true))
    print("Gate checks passed")
```

### Assignment
1. Complete all eight gate rows with predictions.
2. Execute or assert each result in GateLab.

### Acceptance checks
- Exactly one combination opens the original gate.
- All eight inputs are distinct and present.

**Submit:** Eight-row truth table and assertion project.

**Question:** How many combinations would four independent Boolean flags have?

**Support:** Use the C-PUZZLE pure function and a paper truth table before attaching conditions to UI. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Find a logically equivalent expression and verify all eight truth-table rows. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)

---

## VGC-L053 — Give an item once and remember it

**Objective:** Use a state flag to prevent repeated rewards.

**Time:** 55 minutes

### Instruction
A story passage may be revisited many times. If visiting the keeper always adds a key, a player can duplicate a supposedly unique object. Store has_key as a Boolean and grant the key only if it is false. Change the dialogue after collection so the world acknowledges the event. Keep the condition and the effect distinct: “does the player have a key?” is a question, while “set has_key to true” changes state. Restart must reset this flag unless deliberate persistence is introduced later.

### Worked example
A separate practice door might require badge OR helper_present. Test each Boolean combination on paper before using the function to show an Open button.

Scaffold C-DIALOGUE — Data-driven branching dialogue without personal data
Setup: Create Control root Dialogue with VBoxContainer Box containing Label Line and Buttons A and B. Set Box anchors to full rect; Line autowrap if needed. Attach script to Dialogue. Data keys are fictional scene IDs. All three screens can fit in 640x360. This is a self-contained example; replace story text in the assignment.
```gdscript
extends Control
var page: String = "start"
var story: Dictionary = {
    "start": {"text": "Two paths enter the archive.", "choices": [["Ask the keeper", "keeper"], ["Read a sign", "sign"]]},
    "keeper": {"text": "The keeper offers a map.", "choices": [["Return", "start"]]},
    "sign": {"text": "Quiet room to the east.", "choices": [["Return", "start"]]}
}
func _ready() -> void:
    $Box/A.pressed.connect(_choose.bind(0))
    $Box/B.pressed.connect(_choose.bind(1))
    _show()
func _show() -> void:
    var entry: Dictionary = story[page]
    $Box/Line.text = entry["text"]
    var buttons: Array[Button] = [$Box/A, $Box/B]
    for i in range(buttons.size()):
        buttons[i].visible = i < entry["choices"].size()
        if buttons[i].visible:
            buttons[i].text = entry["choices"][i][0]
    $Box/A.grab_focus()
func _choose(index: int) -> void:
    var choices: Array = story[page]["choices"]
    if index < 0 or index >= choices.size():
        return
    page = str(choices[index][1])
    _show()
```

Scaffold C-PUZZLE — A testable gate rule
Setup: Create Node root GateLab and attach this script. The pure gate_open function does not read input or change a scene. A level can call it with its inventory and lever state. Assertions run on start. For the assignment write additional tests before changing the rule.
```gdscript
extends Node
func gate_open(has_key: bool, lever_on: bool, alarm_on: bool) -> bool:
    return has_key and lever_on and not alarm_on
func _ready() -> void:
    assert(gate_open(true, true, false))
    assert(not gate_open(false, true, false))
    assert(not gate_open(true, false, false))
    assert(not gate_open(true, true, true))
    print("Gate checks passed")
```

### Assignment
1. Add a once-only key reward and a changed repeat-visit passage.
2. Visit the keeper three times and restart.

### Acceptance checks
- Repeated visits do not duplicate the reward.
- Restart returns to the documented initial possession state.

**Submit:** Story project with key-state trace.

**Question:** Why is a condition not the same as an assignment?

**Support:** Use the C-PUZZLE pure function and a paper truth table before attaching conditions to UI. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Find a logically equivalent expression and verify all eight truth-table rows. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)

---

## VGC-L054 — Reveal a puzzle through feedback

**Objective:** Explain failure without giving the whole answer immediately.

**Time:** 55 minutes

### Instruction
A locked gate should tell the player enough to make a next decision. Distinguish “key missing,” “lever off,” and “alarm active” rather than showing the same vague failure. You may reveal one unmet condition at a time in a documented priority order. Do not punish experimentation with a permanent unwinnable state. Write a hint ladder: a gentle reminder, a more specific clue and an explicit solution available on request. Hints are an accessibility feature, not evidence that the learner failed.

### Worked example
A separate practice door might require badge OR helper_present. Test each Boolean combination on paper before using the function to show an Open button.

Scaffold C-DIALOGUE — Data-driven branching dialogue without personal data
Setup: Create Control root Dialogue with VBoxContainer Box containing Label Line and Buttons A and B. Set Box anchors to full rect; Line autowrap if needed. Attach script to Dialogue. Data keys are fictional scene IDs. All three screens can fit in 640x360. This is a self-contained example; replace story text in the assignment.
```gdscript
extends Control
var page: String = "start"
var story: Dictionary = {
    "start": {"text": "Two paths enter the archive.", "choices": [["Ask the keeper", "keeper"], ["Read a sign", "sign"]]},
    "keeper": {"text": "The keeper offers a map.", "choices": [["Return", "start"]]},
    "sign": {"text": "Quiet room to the east.", "choices": [["Return", "start"]]}
}
func _ready() -> void:
    $Box/A.pressed.connect(_choose.bind(0))
    $Box/B.pressed.connect(_choose.bind(1))
    _show()
func _show() -> void:
    var entry: Dictionary = story[page]
    $Box/Line.text = entry["text"]
    var buttons: Array[Button] = [$Box/A, $Box/B]
    for i in range(buttons.size()):
        buttons[i].visible = i < entry["choices"].size()
        if buttons[i].visible:
            buttons[i].text = entry["choices"][i][0]
    $Box/A.grab_focus()
func _choose(index: int) -> void:
    var choices: Array = story[page]["choices"]
    if index < 0 or index >= choices.size():
        return
    page = str(choices[index][1])
    _show()
```

Scaffold C-PUZZLE — A testable gate rule
Setup: Create Node root GateLab and attach this script. The pure gate_open function does not read input or change a scene. A level can call it with its inventory and lever state. Assertions run on start. For the assignment write additional tests before changing the rule.
```gdscript
extends Node
func gate_open(has_key: bool, lever_on: bool, alarm_on: bool) -> bool:
    return has_key and lever_on and not alarm_on
func _ready() -> void:
    assert(gate_open(true, true, false))
    assert(not gate_open(false, true, false))
    assert(not gate_open(true, false, false))
    assert(not gate_open(true, true, true))
    print("Gate checks passed")
```

### Assignment
1. Implement distinct gate feedback and a three-step hint ladder.
2. Test each unmet condition and the solved state.

### Acceptance checks
- Every blocked state suggests a meaningful next action.
- The solved message is not shown for an unsolved gate.

**Submit:** Gate-feedback table, hint text and project.

**Question:** Why avoid a permanently consumed key when the only gate remains locked?

**Support:** Use the C-PUZZLE pure function and a paper truth table before attaching conditions to UI. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Find a logically equivalent expression and verify all eight truth-table rows. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)

---

## VGC-L055 — Validate the puzzle graph

**Objective:** Test reachability, reset and alternate routes.

**Time:** 55 minutes

### Instruction
A story can contain correct local conditions while its overall graph is broken. Walk every arrow and record the destination, then test whether each required item can be obtained before the gate needs it. Try the least helpful order of actions, not only the ideal route. Check restart after both endings. Use a small route table containing start state, action sequence and expected ending. This is a manual integration test of navigation, state and logic together.

### Worked example
A separate practice door might require badge OR helper_present. Test each Boolean combination on paper before using the function to show an Open button.

Scaffold C-DIALOGUE — Data-driven branching dialogue without personal data
Setup: Create Control root Dialogue with VBoxContainer Box containing Label Line and Buttons A and B. Set Box anchors to full rect; Line autowrap if needed. Attach script to Dialogue. Data keys are fictional scene IDs. All three screens can fit in 640x360. This is a self-contained example; replace story text in the assignment.
```gdscript
extends Control
var page: String = "start"
var story: Dictionary = {
    "start": {"text": "Two paths enter the archive.", "choices": [["Ask the keeper", "keeper"], ["Read a sign", "sign"]]},
    "keeper": {"text": "The keeper offers a map.", "choices": [["Return", "start"]]},
    "sign": {"text": "Quiet room to the east.", "choices": [["Return", "start"]]}
}
func _ready() -> void:
    $Box/A.pressed.connect(_choose.bind(0))
    $Box/B.pressed.connect(_choose.bind(1))
    _show()
func _show() -> void:
    var entry: Dictionary = story[page]
    $Box/Line.text = entry["text"]
    var buttons: Array[Button] = [$Box/A, $Box/B]
    for i in range(buttons.size()):
        buttons[i].visible = i < entry["choices"].size()
        if buttons[i].visible:
            buttons[i].text = entry["choices"][i][0]
    $Box/A.grab_focus()
func _choose(index: int) -> void:
    var choices: Array = story[page]["choices"]
    if index < 0 or index >= choices.size():
        return
    page = str(choices[index][1])
    _show()
```

Scaffold C-PUZZLE — A testable gate rule
Setup: Create Node root GateLab and attach this script. The pure gate_open function does not read input or change a scene. A level can call it with its inventory and lever state. Assertions run on start. For the assignment write additional tests before changing the rule.
```gdscript
extends Node
func gate_open(has_key: bool, lever_on: bool, alarm_on: bool) -> bool:
    return has_key and lever_on and not alarm_on
func _ready() -> void:
    assert(gate_open(true, true, false))
    assert(not gate_open(false, true, false))
    assert(not gate_open(true, false, false))
    assert(not gate_open(true, true, true))
    print("Gate checks passed")
```

### Assignment
1. Test every story arrow and at least three action orders.
2. Repair one discovered issue or document a deliberately injected link fault and fix.

### Acceptance checks
- All intended endings are reachable.
- No legal action order makes the required goal permanently impossible.

**Submit:** Complete graph audit and repaired Archive Lantern checkpoint.

**Question:** Can a correct gate function guarantee the story is completable?

**Support:** Use the C-PUZZLE pure function and a paper truth table before attaching conditions to UI. Start with the first assigned task and re-run its acceptance test before adding the remaining feature.

**Optional extension:** Find a logically equivalent expression and verify all eight truth-table rows. Document one changed parameter, your prediction, and the observed effect; optional, not required for completion.

**Optional free reading:** [Godot step by step: nodes, scenes, GDScript, input, signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html)

---