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 workflowsoutput identical to the compiled C program, byte for byte
$ ./program < coffee-run.txt
exit 0tracing message 4 of 6
- inread from stdinInput: Traffic,is,awful,>:(,:-/,!!
- 2strip letters, digitsAfter stage 2: ,,,>:(,:-/,!!
- 3tidy commasAfter stage 3: >:(,:-/,!!
- 4read dictionaryStage 4: 8 emoticons, longest \(^_^)/
- 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:
- Coffee,before,class?,:-),:-)messages, one per line
- Sure,meet,at,8,;-),see,youspaces became commas
- ###separator
- :-),happydictionary: emoticon,emotion
- ;-),wink
- 1CountRead the first messageRead the first line and count its tokens by counting commas.stage_one() count_tokens()
- 2StripStrip letters and digitsRead every message up to ### and keep only punctuation, commas included.stage_two()
- 3CommasTidy the commasRemove leading, trailing and repeated commas so tokens are one comma apart.stage_three()
- 4DictionaryRead the dictionaryRead the emoticon dictionary, then report its size and its longest entry.stage_four()
- 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.
A 50-byte first line
The first message is read with the emoticon limit (50) instead of the message limit (280), so a long opening line ends the program in stage 1.
Trip the limitMessages that merge
Stage 5 prints a newline only if a message's last token survives. Drop that token and the next message runs straight on.
See the mergeA 2,500-byte scratch buffer
Stage 5 tokenises everything into char list[50][50]. Around 25 messages overflow it, and the compiled binary aborts.
Overflow it
// 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_msgandprint_stage_headercame 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=c99and 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.