Skip to content

COMP10002 · Foundations of Algorithms · 2020

Cleansing emoticons,
one stage at a time

My first-year C assignment reads chat messages, strips everything that is not an emoticon, and checks what is left against a dictionary. This site runs a line-by-line TypeScript port of that program in your browser, so you can watch each of the five stages do its work.

Watch the tour: three recorded workflows

output identical to the compiled C program, byte for byte

$ ./program < coffee-run.txt

exit 0

tracing message 4 of 6

  1. inread from stdinInput: Traffic,is,awful,>:(,:-/,!!
  2. 2strip letters, digitsAfter stage 2: ,,,>:(,:-/,!!
  3. 3tidy commasAfter stage 3: >:(,:-/,!!
  4. 4read dictionaryStage 4: 8 emoticons, longest \(^_^)/
  5. 5keep known emoticonsAfter stage 5: >:(,:-/,. Removed: !!

stdout, stage 5

>:(,:-/,\(^_^)/

The last token was dropped, so the original never prints this message's newline and the next message runs on. The port keeps that quirk.

// the assignment

Turn noisy posts into clean emoticon data

Text-analysis tools stumble over emoticons, so the task was a data-cleansing step: given social-media style messages and a small dictionary of known emoticons, keep only the valid emoticons in each message.

It was an individual exercise in arrays, strings and careful input handling, written in C99 on top of a staff skeleton whose main could not be changed. Everything arrives on standard input:

input.txt (an example written for this site)
  1. Coffee,before,class?,:-),:-)messages, one per line
  2. Sure,meet,at,8,;-),see,youspaces became commas
  3. ###separator
  4. :-),happydictionary: emoticon,emotion
  5. ;-),wink
  1. 1CountRead the first messageRead the first line and count its tokens by counting commas.stage_one() count_tokens()
  2. 2StripStrip letters and digitsRead every message up to ### and keep only punctuation, commas included.stage_two()
  3. 3CommasTidy the commasRemove leading, trailing and repeated commas so tokens are one comma apart.stage_three()
  4. 4DictionaryRead the dictionaryRead the emoticon dictionary, then report its size and its longest entry.stage_four()
  5. 5ValidateDrop unknown emoticonsWithout string.h, keep only tokens that appear in the dictionary.stage_five() emotionexisitence()

// what I built

A complete solution, then a faithful port

In 2020 I filled in all five stages and a hand-written string comparison for stage 5, which had to avoid string.h. The program reproduces both sample outputs that came with the assignment.

The revival does not improve the algorithm. Each C function was ported to TypeScript loop for loop, and a test suite checks the port against the compiled original on the sample tests and on a set of edge cases recorded from the real binary.

official sample tests passed by the 2020 program, byte for byte
2/2
95% CI 34.2% to 100% (Wilson)
lines of C99, with 7 functions completed by me
347
hand-picked runs of the compiled binary reproduced exactly by the TypeScript port
39/39
95% CI 91.0% to 100% (Wilson)
inputs that crash the original, flagged and explained instead
2

// kept on purpose

Quirks you can poke at

Student code has edges. Rather than quietly fixing them, the port reproduces them and the visualiser explains what happens, so the behaviour on screen is the behaviour that was submitted.

// evidence, with uncertainty

Tested against the original, then against an LLM

Every claim on this site is backed by a test you can rerun, and every rate comes with its sample size and a confidence interval. The methods page sets out the data, the tests and their limits.

  • 481/481

    Differential testing

    Seeded random inputs, concentrated on the program's limits, reproduced byte for byte by the port (95% CI 99.2% to 100%). The 19 inputs that crash the C binary are flagged instead.

    Read the method
  • BYOK

    Rules vs LLM

    Ask an LLM to follow the same procedure and score it against the rule engine, with Wilson and bootstrap intervals and a paired McNemar test. Bring your own key, or run the non-AI baselines without one.

    Run the evaluation
  • 5

    Decision records

    Why the source was recovered verbatim, why byte parity is the bar, how Windows line endings are handled, and how the LLM evaluation and API keys are designed.

    See the decisions

// about this project

From a 2020 submission to a 2026 revival

The final source was recovered from my study notes in 2026 and is preserved unchanged in the repository. The assignment specification belongs to the University and is paraphrased here rather than reproduced.

Subject
COMP10002 Foundations of Algorithms
University
The University of Melbourne
When
Semester 1, 2020 · Assignment 1 (individual)
Credits
Solution by Sunchuangyu (Rin) Huang. The fixed main, read_one_msg and print_stage_header came from the skeleton by the teaching staff (Farhana Choudhury and Jianzhong Qi).
Original stack
C99 and the standard library only (no string.h in stage 5), compiled with gcc -Wall -std=c99 and tested by piping text files into stdin.
Revived stack
Next.js 16 (static), TypeScript, Tailwind CSS v4, shadcn/ui, Motion, Shiki and Vitest. No server: the port runs in your browser.
Integrity
Published after the subject finished, for portfolio purposes. If you are taking COMP10002 now, please do your own work.