diff --git a/examples/gno.land/p/demo/tamagotchi/gno.mod b/examples/gno.land/p/demo/tamagotchi/gno.mod new file mode 100644 index 00000000000..22c59d611a2 --- /dev/null +++ b/examples/gno.land/p/demo/tamagotchi/gno.mod @@ -0,0 +1,3 @@ +module gno.land/r/demo/tamagotchi + +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/p/demo/tamagotchi/tamagotchi.gno b/examples/gno.land/p/demo/tamagotchi/tamagotchi.gno new file mode 100644 index 00000000000..04e74a3d9c1 --- /dev/null +++ b/examples/gno.land/p/demo/tamagotchi/tamagotchi.gno @@ -0,0 +1,177 @@ +package tamagotchi + +// this file could be moved to p/demo/tamagotchi. + +import ( + "time" + + "gno.land/p/demo/ufmt" +) + +// Tamagotchi structure +type Tamagotchi struct { + name string + hunger int + happiness int + health int + age int + maxAge int + sleepy int + created time.Time + lastUpdated time.Time +} + +func New(name string) *Tamagotchi { + now := time.Now() + return &Tamagotchi{ + name: name, + hunger: 50, + happiness: 50, + health: 50, + maxAge: 100, + lastUpdated: now, + created: now, + } +} + +func (t *Tamagotchi) Name() string { + t.update() + return t.name +} + +func (t *Tamagotchi) Hunger() int { + t.update() + return t.hunger +} + +func (t *Tamagotchi) Happiness() int { + t.update() + return t.happiness +} + +func (t *Tamagotchi) Health() int { + t.update() + return t.health +} + +func (t *Tamagotchi) Age() int { + t.update() + return t.age +} + +func (t *Tamagotchi) Sleepy() int { + t.update() + return t.sleepy +} + +// Feed method for Tamagotchi +func (t *Tamagotchi) Feed() { + t.update() + if t.dead() { + return + } + t.hunger = bound(t.hunger-10, 0, 100) +} + +// Play method for Tamagotchi +func (t *Tamagotchi) Play() { + t.update() + if t.dead() { + return + } + t.happiness = bound(t.happiness+10, 0, 100) +} + +// Heal method for Tamagotchi +func (t *Tamagotchi) Heal() { + t.update() + + if t.dead() { + return + } + t.health = bound(t.health+10, 0, 100) +} + +func (t Tamagotchi) dead() bool { return t.health == 0 } + +// Update applies changes based on the duration since the last update +func (t *Tamagotchi) update() { + if t.dead() { + return + } + + now := time.Now() + if t.lastUpdated == now { + return + } + + duration := now.Sub(t.lastUpdated) + elapsedMins := int(duration.Minutes()) + + t.hunger = bound(t.hunger+elapsedMins, 0, 100) + t.happiness = bound(t.happiness-elapsedMins, 0, 100) + t.health = bound(t.health-elapsedMins, 0, 100) + t.sleepy = bound(t.sleepy+elapsedMins, 0, 100) + + // age is hours since created + t.age = int(now.Sub(t.created).Hours()) + if t.age > t.maxAge { + t.age = t.maxAge + t.health = 0 + } + if t.health == 0 { + t.sleepy = 0 + t.happiness = 0 + t.hunger = 0 + } + + t.lastUpdated = now +} + +// Face returns an ASCII art representation of the Tamagotchi's current state +func (t *Tamagotchi) Face() string { + t.update() + return t.face() +} + +func (t *Tamagotchi) face() string { + switch { + case t.health == 0: + return "😵" // dead face + case t.health < 30: + return "😷" // sick face + case t.happiness < 30: + return "😢" // sad face + case t.hunger > 70: + return "😫" // hungry face + case t.sleepy > 70: + return "😴" // sleepy face + default: + return "😃" // happy face + } +} + +// Markdown method for Tamagotchi +func (t *Tamagotchi) Markdown() string { + t.update() + return ufmt.Sprintf(`# %s %s + +* age: %d +* hunger: %d +* happiness: %d +* health: %d +* sleepy: %d`, + t.name, t.Face(), + t.age, t.hunger, t.happiness, t.health, t.sleepy, + ) +} + +func bound(n, min, max int) int { + if n < min { + return min + } + if n > max { + return max + } + return n +} diff --git a/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno b/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno new file mode 100644 index 00000000000..fcdcb5ab198 --- /dev/null +++ b/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno @@ -0,0 +1,106 @@ +package main + +import ( + "std" + "time" + + "internal/os_test" + + "gno.land/p/demo/tamagotchi" +) + +func main() { + t := tamagotchi.New("Gnome") + + println("\n-- INITIAL\n") + println(t.Markdown()) + + println("\n-- WAIT 20 minutes\n") + os_test.Sleep(20 * time.Minute) + println(t.Markdown()) + + println("\n-- FEEDx3, PLAYx2, HEALx4\n") + t.Feed() + t.Feed() + t.Feed() + t.Play() + t.Play() + t.Heal() + t.Heal() + t.Heal() + t.Heal() + println(t.Markdown()) + + println("\n-- WAIT 20 minutes\n") + os_test.Sleep(20 * time.Minute) + println(t.Markdown()) + + println("\n-- WAIT 20 hours\n") + os_test.Sleep(20 * time.Hour) + println(t.Markdown()) + + println("\n-- WAIT 20 hours\n") + os_test.Sleep(20 * time.Hour) + println(t.Markdown()) +} + +// Output: +// -- INITIAL +// +// # Gnome 😃 +// +// * age: 0 +// * hunger: 50 +// * happiness: 50 +// * health: 50 +// * sleepy: 0 +// +// -- WAIT 20 minutes +// +// # Gnome 😃 +// +// * age: 0 +// * hunger: 70 +// * happiness: 30 +// * health: 30 +// * sleepy: 20 +// +// -- FEEDx3, PLAYx2, HEALx4 +// +// # Gnome 😃 +// +// * age: 0 +// * hunger: 40 +// * happiness: 50 +// * health: 70 +// * sleepy: 20 +// +// -- WAIT 20 minutes +// +// # Gnome 😃 +// +// * age: 0 +// * hunger: 60 +// * happiness: 30 +// * health: 50 +// * sleepy: 40 +// +// -- WAIT 20 hours +// +// # Gnome 😵 +// +// * age: 20 +// * hunger: 100 +// * happiness: 0 +// * health: 0 +// * sleepy: 100 +// +// -- WAIT 20 hours +// +// # Gnome 😵 +// +// * age: 20 +// * hunger: 100 +// * happiness: 0 +// * health: 0 +// * sleepy: 100 diff --git a/examples/gno.land/r/demo/tamagotchi/gno.mod b/examples/gno.land/r/demo/tamagotchi/gno.mod new file mode 100644 index 00000000000..b7a2deea2c2 --- /dev/null +++ b/examples/gno.land/r/demo/tamagotchi/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/demo/tamagotchi + +require ( + gno.land/p/demo/tamagotchi v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) diff --git a/examples/gno.land/r/demo/tamagotchi/realm.gno b/examples/gno.land/r/demo/tamagotchi/realm.gno new file mode 100644 index 00000000000..f8f62c9fc7a --- /dev/null +++ b/examples/gno.land/r/demo/tamagotchi/realm.gno @@ -0,0 +1,53 @@ +package tamagotchi + +import ( + "std" + + "gno.land/p/demo/tamagotchi" + "gno.land/p/demo/ufmt" +) + +var t *tamagotchi.Tamagotchi + +func init() { + Reset("gnome#0") +} + +func Reset(optionalName string) string { + name := optionalName + if name == "" { + height := std.GetHeight() + name = ufmt.Sprintf("gnome#%d", height) + } + + t = tamagotchi.New(name) + + return ufmt.Sprintf("A new tamagotchi is born. Their name is %s %s.", t.Name(), t.Face()) +} + +func Feed() string { + t.Feed() + return t.Markdown() +} + +func Play() string { + t.Play() + return t.Markdown() +} + +func Heal() string { + t.Heal() + return t.Markdown() +} + +func Render(path string) string { + tama := t.Markdown() + links := `Actions: +* [Feed](/r/demo/tamagotchi?help&__func=Feed) +* [Play](/r/demo/tamagotchi?help&__func=Play) +* [Heal](/r/demo/tamagotchi?help&__func=Heal) +* [Reset](/r/demo/tamagotchi?help&__func=Reset) +` + + return tama + "\n\n" + links +} diff --git a/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno b/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno new file mode 100644 index 00000000000..373d737b3b5 --- /dev/null +++ b/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno @@ -0,0 +1,28 @@ +package main + +import ( + "std" + "time" + + "gno.land/r/demo/tamagotchi" +) + +func main() { + tamagotchi.Reset("tamagnotchi") + println(tamagotchi.Render("")) +} + +// Output: +// # tamagnotchi 😃 +// +// * age: 0 +// * hunger: 50 +// * happiness: 50 +// * health: 50 +// * sleepy: 0 +// +// Actions: +// * [Feed](/r/demo/tamagotchi?help&__func=Feed) +// * [Play](/r/demo/tamagotchi?help&__func=Play) +// * [Heal](/r/demo/tamagotchi?help&__func=Heal) +// * [Reset](/r/demo/tamagotchi?help&__func=Reset) diff --git a/gno.land/Makefile b/gno.land/Makefile index 29c192e9987..8751729df78 100644 --- a/gno.land/Makefile +++ b/gno.land/Makefile @@ -5,8 +5,16 @@ help: rundep=go run -modfile ../misc/devdeps/go.mod -.PHONY: gnoland.start -gnoland.start:; go run ./cmd/gnoland start +gnoland.start: + @#TODO: remove this makefile directive in a few weeks. + @echo "DEPRECATED: use 'start.gnoland' instead of 'gnoland.start'" + go run ./cmd/gnoland start + +.PHONY: start.gnoland +start.gnoland:; go run ./cmd/gnoland start + +.PHONY: start.gnoweb +start.gnoweb:; go run ./cmd/gnoweb .PHONY: build build: build.gnoland build.gnokey build.gnoweb build.gnofaucet build.gnotxsync build.genesis diff --git a/misc/loop/Makefile b/misc/loop/Makefile index ab79b058ffb..d18c83fb84a 100644 --- a/misc/loop/Makefile +++ b/misc/loop/Makefile @@ -15,11 +15,11 @@ gnoland_dir := $(abspath ../../gno.land) all: loop -gnoland.start: +start.gnoland: cd $(gnoland_dir) && $(gnoland_bin) start -skip-failing-genesis-txs -genesis-txs-file $(HISTORY_OUTPUT) -gnoland.clean: +clean.gnoland: make -C $(gnoland_dir) fclean -.PHONY: gnoland.start gnoland.clean +.PHONY: start.gnoland clean.gnoland # Starts the backup service # and backs up transactions into a file @@ -36,7 +36,7 @@ save.history: cat $(BACKUP_FILE) >> $(HISTORY_OUTPUT) .PHONY: save.history -loop: gnoland.clean +loop: clean.gnoland # backup history, if needed $(MAKE) save.history || true # run our dev loop diff --git a/misc/loop/run_loop.sh b/misc/loop/run_loop.sh index 99d1e5fbc04..4b186df9a71 100755 --- a/misc/loop/run_loop.sh +++ b/misc/loop/run_loop.sh @@ -22,7 +22,7 @@ echo "Running local development setup" # - start the backup service for transactions ( echo "Starting Gno node..." - make gnoland.start + make start.gnoland teardown ) & (