Files
desktop-tools/liust-50/cmd/liustatus/kaomoji.go
Přemysl Eric Janouch de4379ca2c
All checks were successful
Alpine 3.22 Success
OpenBSD 7.8 Success
Add Toshiba Tec LIUST-A00 utilities
2025-11-17 15:16:21 +01:00

243 lines
4.8 KiB
Go

package main
import (
"math/rand"
"strings"
"time"
)
type kaomojiKind int
const (
kaomojiKindAwake kaomojiKind = iota
kaomojiKindBlink
kaomojiKindFace
kaomojiKindChase
kaomojiKindHappy
kaomojiKindSleep
kaomojiKindSnore
kaomojiKindPeek
)
type kaomojiState struct {
kind kaomojiKind
face string
message string
delay int
}
func (ks *kaomojiState) Format() string {
line := []rune(strings.Repeat(" ", displayWidth))
face := []rune(ks.face)
if x := (len(line) - len(face) + 1) / 2; x < 0 {
copy(line, face)
} else {
copy(line[x:], face)
}
if ks.message != "" {
copy(line[14:], []rune(ks.message))
}
return string(line)
}
func (ks *kaomojiState) Duration() time.Duration {
return time.Millisecond * time.Duration(ks.delay)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func kaomojiNewAwake() kaomojiState {
return kaomojiState{
kind: kaomojiKindAwake,
face: "(o_o)",
message: "",
delay: 2_000 + rand.Intn(4_000),
}
}
func kaomojiNewBlink() kaomojiState {
return kaomojiState{
kind: kaomojiKindBlink,
face: "(-_-)",
message: "",
delay: 100 + rand.Intn(50),
}
}
func kaomojiNewFace() kaomojiState {
faces := []struct {
face, message string
}{
{"(x_x)", "ズキズキ"},
{"(T_T)", "ズーン"},
{"=^.^=", "ニャー"},
{"(>_<)", "ゲップ"},
{"(O_O)", "ジー"},
}
x := faces[rand.Intn(len(faces))]
return kaomojiState{
kind: kaomojiKindFace,
face: x.face,
message: x.message,
delay: 10_000,
}
}
func kaomojiNewChase() kaomojiState {
faces := []string{"(゚ロ゚)", "(゚∩゚)"}
return kaomojiState{
kind: kaomojiKindChase,
face: faces[rand.Intn(len(faces))],
message: "",
delay: 125,
}
}
func kaomojiNewHappy() kaomojiState {
return kaomojiState{
kind: kaomojiKindHappy,
face: "(^_^)",
message: "",
delay: 500,
}
}
func kaomojiNewSleep() kaomojiState {
return kaomojiState{
kind: kaomojiKindSleep,
face: "(-_-)",
message: "",
delay: 10_000,
}
}
func kaomojiNewSnore() kaomojiState {
return kaomojiState{
kind: kaomojiKindSnore,
face: "(-_-)",
message: "グーグー",
delay: 10_000,
}
}
func kaomojiNewPeek() kaomojiState {
faces := []string{"(o_-)", "(-_o)"}
return kaomojiState{
kind: kaomojiKindPeek,
face: faces[rand.Intn(len(faces))],
message: "",
delay: 3_000,
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
func kaomojiAnimateChase(state kaomojiState) (lines []string) {
// The main character is fixed and of fixed width.
var (
normal = []rune("(o_o)")
alert = []rune("(O_O)")
centre = (displayWidth - 4) / 2
chaserLen = len([]rune(state.face))
)
// For simplicity, let the animation run off-screen.
for chaserX := chaserLen + displayWidth; chaserX >= 0; chaserX-- {
line := []rune(strings.Repeat(" ", chaserLen+displayWidth))
chased, chasedX := normal, chaserLen+centre
if chasedX > chaserX-7 {
chased, chasedX = alert, chaserX-7
}
if chasedX >= 0 {
copy(line[chasedX:], chased)
}
copy(line[chaserX:], []rune(state.face))
lines = append(lines, string(line[chaserLen:]))
}
// Return our main character back.
for chasedX := displayWidth; chasedX >= centre; chasedX-- {
line := []rune(strings.Repeat(" ", displayWidth))
copy(line[chasedX:], normal)
lines = append(lines, string(line))
}
return
}
func kaomojiProducer(lines chan<- string) {
state := kaomojiNewAwake()
execute := func() {
lines <- state.Format()
time.Sleep(state.Duration())
}
for {
switch state.kind {
case kaomojiKindAwake:
execute()
switch f := rand.Float32(); {
case f < 0.025:
state = kaomojiNewFace()
case f < 0.050:
state = kaomojiNewChase()
case f < 0.075:
state = kaomojiNewHappy()
case f < 0.100:
state = kaomojiNewSleep()
default:
state = kaomojiNewBlink()
}
case kaomojiKindBlink, kaomojiKindFace:
execute()
state = kaomojiNewAwake()
case kaomojiKindHappy:
face := state.face
execute()
state.face = " " + face
execute()
state.face = face
execute()
state.face = face + " "
execute()
state.face = face
execute()
state = kaomojiNewAwake()
case kaomojiKindChase:
for _, line := range kaomojiAnimateChase(state) {
lines <- line
time.Sleep(state.Duration())
}
state = kaomojiNewAwake()
case kaomojiKindSleep:
execute()
switch f := rand.Float32(); {
case f < 0.10:
state = kaomojiNewAwake()
case f < 0.20:
state = kaomojiNewPeek()
case f < 0.60:
state = kaomojiNewSnore()
default:
state = kaomojiNewSleep()
}
case kaomojiKindSnore:
execute()
state = kaomojiNewSleep()
case kaomojiKindPeek:
execute()
state = kaomojiNewSleep()
}
}
}