[List of posts | playground | source code for this post]
So far in this series we've mostly focussed on mazes. So I thought I'd try something completely different: flags!
Vexillilogy (the study of flags) is full of patterns, which lends itself beautifully to procedural generation. So I've created a flag generator which randomly generates realistic-looking flags, including the flags shown above. Why not have a go yourself? You can even download and share your favourites.
In this article I'll give a brief overview of the building blocks which make up my flag generator.
Colours
First off, I needed a colour palette. Flags tend towards bright colours and away from pastels, so I've picked a range of bright colours similar to those you'd find on country flags.
The generator selects randomly from these twelve colours, with two particular caveats.
- Certain colour combinations are not so easy on the eyes (e.g. dark blue and dark green), so I've implemented restrictions on which colours can be placed next to each other.
- Certain colours (your reds, your whites, your blues) are much more common than others (looking at you, purple), so I've weighted them to keep the flags looking realistic.
Patterns
Next, how should the colours be arranged? There are a number of common patterns; here are the twelve I have chosen to use.
Some patterns have additional variations. For example, diagonals can go either way, there can be varying numbers of stripes, and bisections and trisections can be uneven.
Decorations
Some flag patterns lend themselves nicely to additional decoration. A particular favourite of mine is fimbriation: a thin stripe which emphasises the border between two colours.
Another concept seen in real country flags is to add extra blocks of colour to the hoist (that is, the side nearest the flagpole).
Charges
A charge is an emblem added on top of the basic pattern of a flag; I've chosen six simple variations.
The size and placement of any charges depend on the pattern underneath. For example, if your base pattern is a vertical bisection then it makes most sense for a charge to be placed in either the left or right half of the flag. A solid flag is most likely to have an extra-large charge right in the centre.
Technical details
If you're not a programmer, feel free to skip this bit!
Much of the implementation of my flag generator follows similar principles to the previous posts in this series, such as composition of distributions. However I'd like to particularly highlight the concept of a discriminated union, which was super helpful here.
A discriminated union is a type whose values can take any one of a fixed set of types. If you're familiar with C# this might sound like an enumeration, but a discriminated union allows you to assign additional properties to the individual values. For example, each flag pattern has a different set of additional properties: a solid flag just needs a single colour defined, whereas a triband flag needs three. This makes a discriminated union an ideal data type to represent a flag pattern.
[Union]
public partial record FlagPattern
{
public partial record Solid(FlagColour Field);
public partial record VerticalBisection(FlagColour Left, FlagColour Right);
public partial record HorizontalBisection(FlagColour Top, FlagColour Bottom, HorizontalBisectionDecoration Decoration);
public partial record VerticalTriband(FlagColour Left, FlagColour Middle, FlagColour Right);
public partial record HorizontalTriband(FlagColour Top, FlagColour Middle, FlagColour Bottom, HorizontalTribandSizing Sizing, FlagColour? Fimbriation);
public partial record DiagonalBisection(FlagColour Left, FlagColour Right, Diagonal Diagonal, DiagonalBisectionDecoration Decoration);
public partial record DiagonalBand(FlagColour Field, FlagColour Band, Diagonal Diagonal, FlagColour? Fimbriation);
public partial record Cross(FlagColour Field, FlagColour Foreground, CrossType CrossType);
public partial record Saltire(FlagColour NorthSouthField, FlagColour EastWestField, FlagColour Foreground, FlagColour? Fimbriation);
public partial record Quadrisection(FlagColour TopLeft, FlagColour TopRight, FlagColour BottomRight, FlagColour BottomLeft);
public partial record HorizontalStriped(FlagColour Colour1, FlagColour Colour2, int StripeCount);
public partial record Pall(FlagColour Field, FlagColour Foreground, FlagColour? Fimbriation);
}
Support for discriminated unions has been considered for C# for many years, and it’s finally coming in C# 15 later this year. In the meantime, I’ve used a package called Dunet to implement the discriminated unions I need. It’s particularly helpful in that the compiler will warn you if you have failed to consider one of the allowed values.
Conclusion
Of all the articles in this series, this has probably been my favourite to write! The variety of flags I've been able to generate from a handful of simple rules has been incredible. Sometimes I simply open up the flag generator and share my favourite designs with friends and family.
I've probably taken this as far as I want to for now, but some of my ideas for future expansion include:
- More base patterns, such as a canton (a rectangular emblem in the top-left corner)
- More charge shapes, such as animal designs (my wife really wants me to include a cat!)
- Multiple charges on one flag (such as the Southern Cross constellation on the flag of Australia)
- More colour variations, including different shades of the same hue
- Different aspect ratios or even non-rectangular flags (check out the flag of Nepal if you haven't already!)
And just for fun, here's six more of my favourites!
Further reading
I found the following Wikipedia articles very helpful while researching flag designs!