The "life" of an emoji is simple:
š¶šæ ā š§šæ ā š©šæ ā š±šæāāļø ā š©šæāāļø ā šµšæ
It contains aging from a baby to grown-up person, one profession, and oldness.
And as we have four colors, two genders, five ages, and 22 professions. We can have a great variety of lives. So as the first thing to do I decided to generate all those variants. Initially, I was planning to implement everything in Go, but it's not possible to use emojis in Go code, only codepoints. Because of that, I decided to write a little Python script, that will generate Go code with all variants with codepoints instead of emojis.
For that I just copied lines with emojis from getemoji.com and put them in lists:
ages = [
"š¶ š¦ š§ šØ š© š±āāļø š± š“ šµ",
"š¶š» š¦š» š§š» šØš» š©š» š±š»āāļø š±š» š“š» šµš»",
"š¶š¼ š¦š¼ š§š¼ šØš¼ š©š¼ š±š¼āāļø š±š¼ š“š¼ šµš¼",
"š¶š½ š¦š½ š§š½ šØš½ š©š½ š±š½āāļø š±š½ š“š½ šµš½",
"š¶š¾ š¦š¾ š§š¾ šØš¾ š©š¾ š±š¾āāļø š±š¾ š“š¾ šµš¾",
"š¶šæ š¦šæ š§šæ šØšæ š©šæ š±šæāāļø š±šæ š“šæ šµšæ",
]
ages = [x.split(' ') for x in ages]
roles = [
"š®āāļø š® š·āāļø š· šāāļø š šµļøāāļø šµļø š©āāļø šØāāļø š©āš¾ šØāš¾ š©āš³ šØāš³ š©āš šØāš š©āš¤ šØāš¤ š©āš« šØāš« š©āš šØāš š©āš» šØāš» š©āš¼ šØāš¼ š©āš§ šØāš§ š©āš¬ šØāš¬ š©āšØ šØāšØ š©āš šØāš š©āāļø šØāāļø š©āš šØāš š©āāļø šØāāļø š¤¶ š
šø š¤“",
"š®š»āāļø š®š» š·š»āāļø š·š» šš»āāļø šš» šµš»āāļø šµš» š©š»āāļø šØš»āāļø š©š»āš¾ šØš»āš¾ š©š»āš³ šØš»āš³ š©š»āš šØš»āš š©š»āš¤ šØš»āš¤ š©š»āš« šØš»āš« š©š»āš šØš»āš š©š»āš» šØš»āš» š©š»āš¼ šØš»āš¼ š©š»āš§ šØš»āš§ š©š»āš¬ šØš»āš¬ š©š»āšØ šØš»āšØ š©š»āš šØš»āš š©š»āāļø šØš»āāļø š©š»āš šØš»āš š©š»āāļø šØš»āāļø š¤¶š» š
š» šøš» š¤“š»",
"š®š¼āāļø š®š¼ š·š¼āāļø š·š¼ šš¼āāļø šš¼ šµš¼āāļø šµš¼ š©š¼āāļø šØš¼āāļø š©š¼āš¾ šØš¼āš¾ š©š¼āš³ šØš¼āš³ š©š¼āš šØš¼āš š©š¼āš¤ šØš¼āš¤ š©š¼āš« šØš¼āš« š©š¼āš šØš¼āš š©š¼āš» šØš¼āš» š©š¼āš¼ šØš¼āš¼ š©š¼āš§ šØš¼āš§ š©š¼āš¬ šØš¼āš¬ š©š¼āšØ šØš¼āšØ š©š¼āš šØš¼āš š©š¼āāļø šØš¼āāļø š©š¼āš šØš¼āš š©š¼āāļø šØš¼āāļø š¤¶š¼ š
š¼ šøš¼ š¤“š¼",
"š®š½āāļø š®š½ š·š½āāļø š·š½ šš½āāļø šš½ šµš½āāļø šµš½ š©š½āāļø šØš½āāļø š©š½āš¾ šØš½āš¾ š©š½āš³ šØš½āš³ š©š½āš šØš½āš š©š½āš¤ šØš½āš¤ š©š½āš« šØš½āš« š©š½āš šØš½āš š©š½āš» šØš½āš» š©š½āš¼ šØš½āš¼ š©š½āš§ šØš½āš§ š©š½āš¬ šØš½āš¬ š©š½āšØ šØš½āšØ š©š½āš šØš½āš š©š½āāļø šØš½āāļø š©š½āš šØš½āš š©š½āāļø šØš½āāļø š¤¶š½ š
š½ šøš½ š¤“š½",
"š®š¾āāļø š®š¾ š·š¾āāļø š·š¾ šš¾āāļø šš¾ šµš¾āāļø šµš¾ š©š¾āāļø šØš¾āāļø š©š¾āš¾ šØš¾āš¾ š©š¾āš³ šØš¾āš³ š©š¾āš šØš¾āš š©š¾āš¤ šØš¾āš¤ š©š¾āš« šØš¾āš« š©š¾āš šØš¾āš š©š¾āš» šØš¾āš» š©š¾āš¼ šØš¾āš¼ š©š¾āš§ šØš¾āš§ š©š¾āš¬ šØš¾āš¬ š©š¾āšØ šØš¾āšØ š©š¾āš šØš¾āš š©š¾āāļø šØš¾āāļø š©š¾āš šØš¾āš š©š¾āāļø šØš¾āāļø š¤¶š¾ š
š¾ šøš¾ š¤“š¾",
"š®šæāāļø š®šæ š·šæāāļø š·šæ ššæāāļø ššæ šµšæāāļø šµšæ š©šæāāļø šØšæāāļø š©šæāš¾ šØšæāš¾ š©šæāš³ šØšæāš³ š©šæāš šØšæāš š©šæāš¤ šØšæāš¤ š©šæāš« šØšæāš« š©šæāš šØšæāš š©šæāš» šØšæāš» š©šæāš¼ šØšæāš¼ š©šæāš§ šØšæāš§ š©šæāš¬ šØšæāš¬ š©šæāšØ šØšæāšØ š©šæāš šØšæāš š©šæāāļø šØšæāāļø š©šæāš šØšæāš š©šæāāļø šØšæāāļø š¤¶šæ š
šæ šøšæ š¤“šæ",
]
roles = [x.split(' ') for x in roles]
As emojis have a strange order, generation of all variants is a bit tricky, but it's easier than rearranging them in code because my editor doesn't work quite well with emojis:
def get_life(color, gender, role):
yield ages[color][0]
yield ages[color][1 + gender]
yield ages[color][3 + gender]
yield ages[color][6 - gender]
yield roles[color][role * 2 + 1 - gender]
yield ages[color][7 + gender]
>>> list(get_life(0, 0, 0))
['š¶', 'š¦', 'šØ', 'š±', 'š®', 'š“']
def get_variants():
for color in range(len(ages)):
for gender in (0, 1):
for role in range(len(roles[0]) // 2):
yield color, gender, role
>>> list(get_life(*list(get_variants())[23]))
['š¶', 'š§', 'š©', 'š±\u200dāļø', 'š·\u200dāļø', 'šµ']
And after that it's very easy to generate Go package with all possible variants:
code = b'package variants\n\nvar All = [][]string{\n'
for variant in get_variants():
code += b'\t{\n'
for emoji in get_life(*variant):
code += b'\t\t"' + emoji.encode('unicode-escape') + b'",\n'
code += b'\t},\n'
code += b'}\n'
with open('variants/variants.go', 'wb') as f:
f.write(code)
So we'll have something like this in variants/variants.go:
package variants
var All = [][]string{
{
"\U0001f476",
"\U0001f466",
"\U0001f468",
"\U0001f471",
"\U0001f46e",
"\U0001f474",
},
...
}
The logic of the loader isn't that interesting, although I want to highlight some moments. At the high level
we just read lines from a pipe, if there's no new line arrived before tick seconds, we update our emojis:
func main() {
...
go watchApp(lines)
for {
select {
case line, isOpen := <-lines:
...
os.Stdout.WriteString(line)
...
printPeople(people)
case <-time.After(time.Duration(*tick) * time.Second):
people = updatePeople(people, *count)
printPeople(people)
}
}
}
While updating, we can add new emoji, make one emoji older or "kill" the oldest:
func updatePeople(people []*human, count int) []*human {
addNew := rand.Intn(5) == 0
toMakeOlder := canMakeOlder(people)
if addNew || len(toMakeOlder) == 0 {
people = append(people, getRandomHuman())
} else {
index := toMakeOlder[rand.Intn(len(toMakeOlder))]
people[index].position += 1
}
if len(people) > count {
oldest := getOldest(people)
return append(people[:oldest], people[oldest+1:]...)
} else {
return people
}
}
And that's all. You can find the source code on GitHub.