private BitStream Encode(Puzzle puzzle)
        {
            var norm = StaticAnalysis.RemoveOuter(StaticAnalysis.Normalise(puzzle));
            var bs   = new BitStream();

            foreach (var cell in RunLength.Encode(norm.ForEachTile(), this))
            {
                var s = cell.Item1.Cell;
                if (s == puzzle.Definition.Void ||
                    s == puzzle.Definition.Wall)
                {
                    EncodeItem(cell, Control.None, bs);
                }

                if (s == puzzle.Definition.Floor)
                {
                    EncodeItem(cell, Control.Floor, bs);
                }

                if (s == puzzle.Definition.Goal)
                {
                    bs.AddRange(BitStream.Encode(Control.Goal));
                }
                if (s == puzzle.Definition.Crate)
                {
                    bs.AddRange(BitStream.Encode(Control.Crate));
                }
                if (s == puzzle.Definition.CrateGoal)
                {
                    bs.AddRange(BitStream.Encode(Control.CrateGoal));
                }
                if (s == puzzle.Definition.Player)
                {
                    bs.AddRange(BitStream.Encode(Control.Player));
                }
                if (s == puzzle.Definition.PlayerGoal)
                {
                    bs.AddRange(BitStream.Encode(Control.PlayerGoal));
                }
            }

            bs.AddRange(BitStream.Encode(Control.End));
            return(bs);
        }