Spell Maker – Variables-Functions
Lore & Code Tutorial
The Spellmaker’s Forge
An incremental WPF adventure in logic, variables, and UI design
For Beginner–Intermediate C# Learners
Part I: The Spellmaker’s Code — Logic-First Pipeline
ACT 1 — The Gathering of Ingredients
In the land of Caldreth, young spellmakers don’t begin with potions or crystals. They begin with logic.
You are to craft a spell-mixing system. This system must:
- Take two ingredients (from a predefined list)
- Combine them into a named spell, if a known combination exists
- Otherwise, return a null spell (“nothing happens”)
STEP 1 — Create a Spell Logic Sheet (whiteboard or worksheet)
Label this: Logic Pipeline — Phase 1
On paper or whiteboard, list:
- Your 4–6 ingredients (e.g., fire, water, wind, stone, light, shadow)
- Possible valid combinations and the spell name it produces
(e.g.,fire + wind → Flame Burst
) - Rules for invalid combinations (e.g.,
stone + light → ???
= null spell)
Ask yourself:
- What should happen if the same item is mixed with itself?
- Can some spells be created in either order? (
fire + wind
vswind + fire
) - Should case or spacing matter? How should you normalize input?
STEP 2 — Create a Console App in Visual Studio
- Open Visual Studio
- Create a new project:
Type: Console App (.NET 6/7/8)
Name:SpellMaker.Logic
You now begin the first build pipeline: logic before visuals.
STEP 3—Code Your First Spell Combiner (Manual Logic)
You may even print the symbols and use them on the whiteboard to create your logic charts so you can move them around if needed.

Now let’s go to Visual Studio and write our logic In Program.cs
, write a basic input/output loop:
Console.WriteLine("Enter first ingredient:");
string input1 = Console.ReadLine();
Console.WriteLine("Enter second ingredient:");
string input2 = Console.ReadLine();
string spell = Combine(input1, input2);
Console.WriteLine($"Result: {spell}");
Start with a simple Combine
method using basic if
logic.
static string Combine(string a, string b)
{
if ((a == "fire" && b == "wind") || (a == "wind" && b == "fire"))
return "Flame Burst";
if ((a == "water" && b == "light") || (a == "light" && b == "water"))
return "Healing Mist";
return "Nothing happens...";
}
STEP 4 — Refactor: Use Functions and Variables
Encourage naming like:
- Variables = containers:
string ingredient1 = "fire";
- Functions = machines:
Combine()
takes inputs, returns output
Refactor your code to include:
- A reusable
NormalizeInput()
function (cleans casing/spacing) - A
PrintRules()
function that shows valid combinations to the user - Optional: a
Loop()
that lets the user try multiple times
Refactor Example – From Logic to Functions
Goal: Break your logic into clean, reusable parts. This makes your code easier to read, expand, and connect with the UI in the next stage.
Updated Program.cs
using System;
namespace SpellMaker.Logic
{
class Program
{
static void Main(string[] args)
{
PrintWelcome();
PrintRules();
while (true)
{
string ingredient1 = GetIngredientInput("first");
if (ingredient1 == "exit") break;
string ingredient2 = GetIngredientInput("second");
if (ingredient2 == "exit") break;
string result = CombineIngredients(ingredient1, ingredient2);
Console.WriteLine($"✨ Result: {result}");
}
Console.WriteLine("🪄 Farewell, young Spellmaker.");
}
static void PrintWelcome()
{
Console.WriteLine("Welcome to the Spellmaker's Forge!");
Console.WriteLine("-----------------------------------");
}
static void PrintRules()
{
Console.WriteLine("Combine two ingredients to create a spell.");
Console.WriteLine("Available ingredients: fire, water, wind, stone, light, shadow");
Console.WriteLine("Type 'exit' to leave the forge.");
}
static string GetIngredientInput(string order)
{
Console.Write($"\nEnter {order} ingredient (or 'exit'): ");
return NormalizeInput(Console.ReadLine());
}
static string NormalizeInput(string input)
{
return input?.Trim().ToLower();
}
static string CombineIngredients(string a, string b)
{
if ((a == "fire" && b == "wind") || (a == "wind" && b == "fire"))
return "Flame Burst";
if ((a == "water" && b == "light") || (a == "light" && b == "water"))
return "Healing Mist";
if (a == b)
return $"Double {a.ToUpper()} — unstable magic!";
return "Nothing happens...";
}
}
}
💡 Why This Refactor Matters
Before | After |
---|---|
Repetitive input logic | GetIngredientInput() function reduces duplication |
Case sensitivity bugs | NormalizeInput() ensures reliable matching |
Hard to read or expand | Modular format makes spell rules easier to scale |
Single block of logic | Named steps match real-world planning stages (Input → Normalize → Combine → Output) |
Optional Extensions (Challenge Learners)
- Turn
CombineIngredients()
into a dictionary-based lookup (bonus challenge) - Add a
ListSpells()
function to preview combinations - Track the number of successful spells cast with a variable
STEP 5 — Upgrade Logic Using Switch / Nested If (Phase 2)
Upgrading Your Spell Logic
Label this on your sheet: Logic Pipeline — Phase 2
Once you’ve tested your core combinations, it’s time to prepare your logic for the chaos of the real magical world. New spells, rare conditions, and special rules are coming — and your code needs to handle them gracefully.
Add to Your Logic Sheet
On your worksheet or whiteboard, brainstorm:
- 🧪 New spell combos (e.g.,
stone + shadow → Dark Armor
) - 🧙 Special conditions
For example:
“fire + shadow” only works ifdarkMode == true
- ⚠️ Edge cases:
What if both ingredients are the same? Should it fizzle, explode, or do something unique?
Why Use switch
Instead of Many if
Statements?
As your spellbook grows, using lots of if
statements becomes hard to read and maintain. switch
(or the modern switch expression
) keeps things clean and organized by focusing on patterns instead of repeated comparisons.
Think of switch
as a spellbinding table — you match ingredients to their outcome in one spot.
Example Using switch
Expression
static string Combine(string a, string b, bool darkMode = false)
{
// Normalize order to avoid repeating patterns
string key = string.Compare(a, b) < 0 ? $"{a}_{b}" : $"{b}_{a}";
return key switch
{
"fire_wind" => "Flame Burst",
"light_water" => "Healing Mist",
"stone_shadow" => "Dark Armor",
"fire_shadow" when darkMode => "Infernal Blaze", // Only works if darkMode is true
_ when a == b => $"Double {a} — unstable magic!",
_ => "Nothing happens..."
};
}
Bonus: What’s Happening Here?
- We combine inputs into a key like
"fire_wind"
for easier lookup - 🎯
switch
checks for known matches - ⚡ We use a
when
clause for conditional spells - ❗ The
_
is a catch-all fallback for invalid combos
Design Reflection
- What became harder as your logic grew?
Keeping track of all combinations and reading through long if-chains - What helped organize it better?
Using aswitch
or dictionary makes the spell logic feel more like a scroll or recipe list
Return to your logic sheet. Add:
- New combos
- Spells with conditions (e.g., mixing “fire” and “shadow” should only work if a special flag is true)
Refactor Combine()
using:
- A switch statement (C# 8+
switch
expression or older form) - At least one nested if to handle a special case
Design reflection:
- What became harder as the logic grew?
- What would help organize this better?
You are now ready to transition into Pipeline 2…
Part II: The Spellmaker’s Workshop — UI-First Pipeline
In Caldreth, spellmakers who master logic are invited to the Forge of Glass — where spells are crafted not by words alone, but by touch and vision.
ACT 2 — The Interface Ritual
Now you will translate your console logic into a full WPF application, but this time, using a UI-first approach.
STEP 6 — UI Planning on Whiteboard
Label this: UI Pipeline — Phase 1
Draw your interface:
- A window with a title
- Two dropdowns or buttons for ingredient selection
- A button labeled Combine
- A text display for the result
- Optional: images for ingredients, and an image for the resulting spell
Ask yourself:
- Where will each element go?
- What will trigger the logic?
- Will the result change colors, text, or images?
STEP 7 — Create a WPF Project in Visual Studio
- New project → WPF App (.NET 6/8)
- Name it:
SpellMaker.UI
- Setup folders:
/Assets/Icons
/Assets/Spells
STEP 8 — Build the UI in XAML
Use a Grid or StackPanel layout to create:
- ComboBox or Buttons for Ingredient 1 and 2
- A “Combine Spell” Button
- A TextBlock for the result
No logic yet — just layout and naming.
STEP 9 — Translate Your Logic to the UI (Code-behind)
In MainWindow.xaml.cs
, wire up your logic from the console app.
Use:
- Your
Combine()
function (adapted for event-driven code) - New visuals if desired (change an image or color based on result)
STEP 10 — Reflect and Iterate
- Add new ingredient images
- Create new visual spell results
- Add a reset button or clear animation
- Think about edge cases and invalid inputs
Optional Final Touches
- Sound effect on spell cast
- Third ingredient for advanced recipes
- “Mana” bar (progress bar that depletes with each use)
Submission and Reflection
Your evidence scroll should include:
- Photos of logic sheet and UI sketch
- Screenshot of console app and WPF app working
- Your reflection: what was gained in each pipeline? What was hard? What would you change?
Next Steps
These are starter code templates for both pipelines, so you aren’t starting from scratch, but you still need to think, plan, and fill in the logic yourself based on your flowchart.
🔧 Starter Code: Logic-First Pipeline (Console App)
✅ Project Name: SpellMaker.Logic
Goal: A minimal, structured console app that you can build on after writing their logic sheet.
Program.cs (Starter)
using System;
namespace SpellMaker.Logic
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to the Spellmaker's Forge!");
PrintIntro();
while (true)
{
Console.Write("\nEnter first ingredient (or 'exit'): ");
string input1 = NormalizeInput(Console.ReadLine());
if (input1 == "exit") break;
Console.Write("Enter second ingredient: ");
string input2 = NormalizeInput(Console.ReadLine());
string result = CombineIngredients(input1, input2);
Console.WriteLine($"Result: {result}");
}
Console.WriteLine("Farewell, Spellmaker.");
}
static void PrintIntro()
{
Console.WriteLine("Combine two ingredients to create a spell.");
Console.WriteLine("Example ingredients: fire, water, light, wind, stone, shadow");
Console.WriteLine("Only certain combinations will work!");
}
static string NormalizeInput(string input)
{
return input?.Trim().ToLower();
}
static string CombineIngredients(string a, string b)
{
// Students will complete this using if/else or switch logic
if ((a == "fire" && b == "wind") || (a == "wind" && b == "fire"))
{
return "Flame Burst";
}
return "Nothing happens...";
}
}
}
Starter Code: UI-First Pipeline (WPF)
Project Name:SpellMaker.UI
Goal: Take your working logic and wire it into a basic visual layout.
MainWindow.xaml (Starter Layout)
<Window x:Class="SpellMaker.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Spellmaker's Workshop" Height="400" Width="600"
Background="#1B1B1B" WindowStartupLocation="CenterScreen">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title -->
<TextBlock Text="Spellmaker's Workshop"
FontSize="24" FontWeight="Bold"
Foreground="White"
HorizontalAlignment="Center" Margin="0,0,0,20"/>
<!-- Ingredient Selectors -->
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Spacing="20">
<ComboBox x:Name="Ingredient1Combo" Width="120" />
<ComboBox x:Name="Ingredient2Combo" Width="120" />
<Button Content="Combine" Click="OnCombineClick" Width="100"/>
</StackPanel>
<!-- Result Display -->
<TextBlock x:Name="ResultText" Grid.Row="2"
Text="Select two ingredients to create a spell."
FontSize="16" TextWrapping="Wrap"
Foreground="LightGray"
Margin="0,30,0,0"
HorizontalAlignment="Center" TextAlignment="Center"/>
</Grid>
</Window>
MainWindow.xaml.cs (Starter Code-Behind)
using System.Windows;
namespace SpellMaker.UI
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Populate ingredient lists
string[] ingredients = { "fire", "water", "wind", "stone", "light", "shadow" };
Ingredient1Combo.ItemsSource = ingredients;
Ingredient2Combo.ItemsSource = ingredients;
}
private void OnCombineClick(object sender, RoutedEventArgs e)
{
string a = Ingredient1Combo.SelectedItem?.ToString()?.ToLower();
string b = Ingredient2Combo.SelectedItem?.ToString()?.ToLower();
if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b))
{
ResultText.Text = "Please select two ingredients.";
return;
}
string result = Combine(a, b);
ResultText.Text = $"Result: {result}";
}
private string Combine(string a, string b)
{
// Copy your logic from the console app here
if ((a == "fire" && b == "wind") || (a == "wind" && b == "fire"))
{
return "Flame Burst";
}
return "Nothing happens...";
}
}
}
Project Folder Suggestions
To keep it organized, you should have created a structure similar to this:
/SpellMaker.UI
├── /Assets
│ ├── /Icons
│ └── /Spells
├── MainWindow.xaml
├── MainWindow.xaml.cs
You can add spell icons later (e.g., flame.png, mist.png) and bind them to spell results.
What’s Included
Pipeline | Project Type | Teaches | Starter |
---|---|---|---|
1: Logic First | Console App | Variables, functions, conditionals | Program.cs |
2: UI First | WPF App | XAML layout, event-driven logic | MainWindow.xaml + .cs |