Knitted Flag
Knitted Flag
Platform: CUSTOM | Category: Misc | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: knitout2_parsing, loop_identity_tracking, tube_unspiraling, front_back_bed_rendering, pixel_font_ocr
Summary
Walkthrough of the CUSTOM Misc Knitted Flag. Task: a knitout-2 industrial-knitting program (pattern.k) hides a flag in a double-knit tube. Solution: ignore the random yarn-carrier colors (decoy), track each loop's identity through every xfer to
Description
I got a new knitting machine to help me with the tablecloths for the restaurant but I accidentally dropped my flag into it. Can you help me unravel it?
We are given a single file pattern.k (~22290 lines) in the knitout-2 format — a textual instruction language for industrial knitting machines. The goal is to recover the flag encoded in the knitted fabric.
Analysis
Format recognition. The header lines ;!knitout-2, ;;Carriers: 1 2 3 4 5 6, followed by inhook 1..6 identify the knitout-2 instruction language. Operation counts:
tuck×20 — cast-on setupknit×19554 — the bodyxfer×2668 — exactly 1334f->band 1334b->fdrop×40 — cast-off
The knit op format is knit <dir> <bed><needle> <carrier>, e.g. knit - f20 1. dir is +/-, bed is f(front) or b(back), needle is 1..20, and carrier 1..5 is the yarn color.
Geometry. This is a tube / double-knit program: a front bed (20 needles) and a back bed (20 needles), circumference 40. Each round is a - pass over needles 20→1, some xfers, a + pass over needles 1→20, more xfers. The balanced xfer operations rotate stitches around the tube (spiral knitting), so a naive "20-stitch course" grid comes out scrambled.
Red herring — the carrier colors. The yarn carriers 1..5 are uniformly random (counts ≈ 4371 / 3452 / 3863 / 3477 / 4391). Rendering pixels colored by carrier produces pure noise in every orientation. Color is NOT the data.
The real signal — fabric STRUCTURE. This is classic double-knit jacquard: for each stitch, whether the loop sits on the front bed or the back bed encodes the image (front = "ink" pixel, back = background; the back face shows the inverse design). The semantic hint in the description — "unravel" the "tablecloths" — points at the knit structure, not the yarn color.
Solution
Un-spiral the tube. To undo the spiral rotation, track each loop's identity through every xfer:
- Maintain a dict
(bed,needle) -> stable wale id. - Cast-on
tuckcreates a new wale id. xfermoves the loop's id to the opposing bed at the same needle (loops[dest] = loops.pop(src)).dropremoves it.
This collapses the rotating tube into exactly 20 stable wales (columns) × 975 passes (rows).
Render. For each knit, plot front-bed stitch = black, back-bed stitch = white, indexed by the stable wale id, then ROTATE_90. The image is ~20 rows tall: the top band (rows 0–8, including descenders) is the front face = readable flag text; the bottom band is its inverse (the back face).
python read-only • copy allowed#!/usr/bin/env python3 # Un-spiral the knitout tube and render front/back-bed structure as a flag image. from PIL import Image lines = open("pattern.k").read().splitlines() ops = [s.split() for ln in lines if (s := ln.strip()) and not s.startswith(';')] loops = {} # (bed,needle) -> stable wale id nw = [0] # next wale id def gw(b, i): k = (b, i) if k not in loops: loops[k] = nw[0]; nw[0] += 1 return loops[k] passes = []; cur = []; last = None for p in ops: if p[0] == 'tuck': # cast-on -> new wale gw(p[2][0], int(p[2][1:])) elif p[0] == 'knit': d = p[1]; bed = p[2][0]; idx = int(p[2][1:]) w = gw(bed, idx) if last is not None and d != last and cur: # new pass on direction flip passes.append(cur); cur = [] last = d cur.append((w, bed)) elif p[0] == 'xfer': # move loop id to opposing bed sk = (p[1][0], int(p[1][1:])); dk = (p[2][0], int(p[2][1:])) if sk in loops: loops[dk] = loops.pop(sk) elif p[0] == 'drop': # cast-off loops.pop((p[1][0], int(p[1][1:])), None) if cur: passes.append(cur) H = len(passes); W = nw[0] # 975 passes x 20 wales img = Image.new('L', (W, H), 0); px = img.load() for y, c in enumerate(passes): for w, bed in c: px[w, y] = 255 if bed == 'b' else 0 # front bed = black ink, back = white rot = img.transpose(Image.ROTATE_90) # flag text now horizontal rot.resize((rot.width * 2, rot.height * 20), Image.NEAREST).save("walebed_rot90.png") # Dump top band as ASCII glyphs for careful manual OCR (include descenders). rw, rh = rot.size; rp = rot.load(); NB = 10 band = [[1 if rp[x, y] else 0 for x in range(rw)] for y in range(NB)] for s in range(3, rw, 12): # ~12px-wide fixed cells for y in range(NB): print("".join('#' if band[y][x] else '.' for x in range(s, min(s + 10, rw)))) print(f"--- cell @ {s} ---")
Read the pixel font carefully. The font is a fixed-width ~10px-wide, 7px-tall pixel font with ascenders and descenders. The flag uses heavy leetspeak with random-looking mixed case and substitutions, so every character must be read exactly. The plaintext message is:
congratulations you have understood knitout and unraveled the tablecloths
Note that "tablecloths" and "unravel" appear verbatim from the challenge description — they were the semantic hint to look at the knit structure, not the yarn color.
Critical reading gotchas (caused many wrong submissions)
- Carrier-color rendering is a deliberate decoy — do not waste time on it.
- Descenders. Truncating glyph cells at 7 rows hides descenders, making
y(in "yOU") look likeu. Extract 10 rows tall to reveal the descender and fixy. lvs1vsi. The font has distinct glyphs:1= top-left flag + wide base serif;i= dot-then-bar;l/L= plain bar (capitalLhas a bottom bar). The flag mixes all of these.ovsOvs0and case are distinguished by glyph height: top row 0 = tall (uppercase/ascender); top row 2 = short (lowercase).- The confirmed flag uses:
REDACTED(lowercaselthen1),kN1t0uT(1and zero),7ab1ECl0thS(1,l, zero),unraV3L3d(capitalVandL). - The metadata listed handoutType "Dynamic", but the flag is a fixed congratulatory sentence — the "dynamic" label is misleading.
Key Takeaways / Lessons
- Mastering knitout2_parsing, loop_identity_tracking, tube_unspiraling, front_back_bed_rendering, pixel_font_ocr was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2024-05-31 • CUSTOM • Knitted Flag • Difficulty: Easy