Tutorials

Spell Maker – Variables-Functions

Estimated reading: 10 minutes 20 views Contributors

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:

  1. Your 4–6 ingredients (e.g., fire, water, wind, stone, light, shadow)
  2. Possible valid combinations and the spell name it produces
    (e.g., fire + wind → Flame Burst)
  3. 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 vs wind + fire)
  • Should case or spacing matter? How should you normalize input?

STEP 2 — Create a Console App in Visual Studio

  1. Open Visual Studio
  2. 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

BeforeAfter
Repetitive input logicGetIngredientInput() function reduces duplication
Case sensitivity bugsNormalizeInput() ensures reliable matching
Hard to read or expandModular format makes spell rules easier to scale
Single block of logicNamed 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 if darkMode == 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 a switch 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

  1. New project → WPF App (.NET 6/8)
  2. Name it: SpellMaker.UI
  3. 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

PipelineProject TypeTeachesStarter
1: Logic FirstConsole AppVariables, functions, conditionalsProgram.cs
2: UI FirstWPF AppXAML layout, event-driven logicMainWindow.xaml + .cs
Share this Doc

Spell Maker – Variables-Functions

Or copy link

CONTENTS

Chat Icon Close Icon