Tamagotchi emulator

From Rosetta Code
Tamagotchi emulator is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

If you don't know what Tamagotchi is, take a look at the Wikipedia page about it.

This task is about creating a Tamagotchi emulator, a virtual pet that you must take care of.

Your virtual pet must, like real pets, at least: get hungry, get bored, age and poop!
Against hunger, you must create a way to feed it. Against boredom, you must play with or pet it. The poop must be cleaned, otherwise the pet might get sick and if it is not cured, it might die from its disease. Finally, the pet should grow older and eventually die.

On screen, your program must display the virtual pet status data - age, hunger and happiness levels, when the pet poops, its poop must also be displayed. Ah, well, an avatar of the pet must be there too, but I guess that's obvious!

What else? Well, use your creativityโ€ฆ
Every pet needs a name. What kind of games, or โ€˜mini gamesโ€™ one can play with his pet? And so on!

But, above of all, have fun!

EchoLisp

The tamagotchi status is saved in permanent storage. The tamagotchi cycles can be started manually, or in the preferences function, or at predefined intervals : every function. The following code may be loaded from the EchoLisp library : (load 'tamagotchi). This tamagotchi does not play, but gets bored, and needs to talk. It must be feed two times between each cycle. It will die at age around 42 (42 cycles).

(define-constant CYCLE_TIME 30000) ;; 30 sec for tests, may be 4 hours, 1 day ...
(string-delimiter "")
(struct tamagotchi (name age food poop bored))

;; utility : display tamagotchi thoughts : transitive verb + complement
(define (tama-talk tama)
(writeln (string-append
   "๐Ÿ˜ฎ : "
   (word-random #:any '( verbe trans inf -vintran)))
   " les " 
   (word-random #:any '(nom pluriel))))

;; load tamagotchi from persistent storage into *tama* global
(define (run-tamagotchi)
	(if (null? (local-get '*tama*))
	    (writeln "Please (make-tamagotchi <name>)")
	(begin 
	    (make-tamagotchi (tamagotchi-name *tama*) *tama*)
	    (tama-cycle *tama*)
	    (writeln (tama-health *tama*)))))
		
;; make a new tamagotchi
;; or instantiate an existing
;; tama : instance ot tamagotchi structure
(define (make-tamagotchi name (tama null))
(when (null? tama) 
		(set! tama (tamagotchi name 0 2 0 0))
		(define-global '*tama* tama)
		(local-put '*tama*))
		
;; define the <name> procedure :
;;  perform user action / save tamagotchi / display status

(define-global name
(lambda (action)
	(define tama (local-get '*tama*))
	[case action
	((feed) (set-tamagotchi-food! tama  (1+  (tamagotchi-food tama))))
	((talk)  (tama-talk tama) (set-tamagotchi-bored! tama (max 0 (1- (tamagotchi-bored tama)))))
	((clean) (set-tamagotchi-poop! tama (max 0 (1- (tamagotchi-poop tama)))))
	((look) #t)
;; debug actions
	((_cycle) (tama-cycle tama))
	((_reset) (set! *tama* null) (local-put '*tama*))
	((_kill) (set-tamagotchi-age! tama 44))
	((_self) (writeln tama))
	(else (writeln "actions: feed/talk/clean/look"))]
	
	(local-put '*tama*)
	(tama-health tama))))
	
;; every n msec : get older / eat food / get bored / poop
(define (tama-cycle tama)
		(when (tama-alive tama)
		(set-tamagotchi-age! tama (1+ (tamagotchi-age tama)))
		(set-tamagotchi-bored! tama (+   (tamagotchi-bored tama) (random 2)))
		(set-tamagotchi-food! tama  (max 0 (-  (tamagotchi-food tama) 2)))
		(set-tamagotchi-poop! tama  (+   (tamagotchi-poop tama) (random 2))))
		(local-put '*tama*))
		
;; compute sickness (too much poop, too much food, too much bored)
(define (tama-sick tama) 	
	 (+ (tamagotchi-poop tama) 
	    (tamagotchi-bored tama) 
	    (max 0 (- (tamagotchi-age tama) 32)) ;; die at 42
	    (abs (-  (tamagotchi-food tama) 2))))
	    
;; alive if sickness <= 10
(define (tama-alive tama)
		(<= (tama-sick tama) 10))
	
;; display num icons from a list
(define (icons list num)
		(for/fold (str "  ") ((i [in-range 0 num] )) 
		(string-append str (list-ref list (random (length list))))))
	
;; display boredom/food/poops icons
(define (tama-status tama)
	(if (tama-alive tama)
		(string-append 
		" [ "
		(icons '(๐Ÿ’ค  ๐Ÿ’ญ โ“ ) (tamagotchi-bored tama))  
		(icons  '(๐Ÿผ ๐Ÿ” ๐ŸŸ ๐Ÿฐ  ๐Ÿœ ) (tamagotchi-food tama))
		(icons '(๐Ÿ’ฉ) (tamagotchi-poop tama))
		" ]")
	    " R.I.P" ))
	
;; display health status = f(sickness)
(define (tama-health tama)
	(define sick (tama-sick tama))
	;;(writeln 'health:sickยฐ= sick)
	(string-append 
	(format "%a (๐ŸŽ‚ %d)  " (tamagotchi-name tama)(tamagotchi-age tama))
	(cond 
	([<= sick 2]   (icons '(๐Ÿ˜„  ๐Ÿ˜ƒ  ๐Ÿ˜€ ๐Ÿ˜Š  ๐Ÿ˜Ž๏ธ  ๐Ÿ‘ ) 1 ))  ;; ok <= 2
	([<= sick 4]   (icons '(๐Ÿ˜ช  ๐Ÿ˜ฅ  ๐Ÿ˜ฐ  ๐Ÿ˜“  )  1))
	([<= sick 6]   (icons '(๐Ÿ˜ฉ  ๐Ÿ˜ซ )  1))
	([<= sick 10]  (icons '(๐Ÿ˜ก  ๐Ÿ˜ฑ ) 1)) ;; very bad
	(else  (icons '(โŒ  ๐Ÿ’€  ๐Ÿ‘ฝ  ๐Ÿ˜‡ ) 1))) ;; dead
    (tama-status tama)))
    
;; timer operations
;; run tama-proc = cycle every CYCLE_TIME msec

(define (tama-proc n)
	(define tama (local-get '*tama*))
	(when (!null? tama)
		(tama-cycle tama)
		(writeln (tama-health tama))))
		
;; boot
;; manual boot or use (preferences) function
(every CYCLE_TIME tama-proc)
(run-tamagotchi)
Output:

User commands are function calls : (albert 'clean). The rest is automatic display : one status line / cycle.

(lib 'struct)
(lib 'sql) ;; for words
(lib 'words)
(lib 'timer)
(lib 'dico.fr);; will talk in french
(load 'tamagotchi)
Please (make-tamagotchi <name>)   
    
    (make-tamagotchi 'albert)

    albert (๐ŸŽ‚ 1) ๐Ÿ˜“ [ ๐Ÿ’ญ ]    
    albert (๐ŸŽ‚ 2) ๐Ÿ˜ฐ [ ๐Ÿ’ญโ“ ]    ;; needs to talk
    (albert 'talk)
    ๐Ÿ˜ฎ : dรฉlรฉaturer     les      fidรจles    
    albert (๐ŸŽ‚ 2) ๐Ÿ˜“ [ โ“ ]
    (albert 'talk)
    ๐Ÿ˜ฎ : facetter     les      dรฉcorations    
    albert (๐ŸŽ‚ 2) ๐Ÿ˜ƒ [ ]
    albert (๐ŸŽ‚ 3) ๐Ÿ˜ฅ [ ๐Ÿ’ค ๐Ÿ’ฉ ]    
    (albert 'feed)
    albert (๐ŸŽ‚ 3) ๐Ÿ˜ช [ ๐Ÿ’ค ๐Ÿ” ๐Ÿ’ฉ ] ;; needs cleaning
    (albert 'clean)
    albert (๐ŸŽ‚ 3) ๐Ÿ˜Š [ ๐Ÿ’ญ ๐ŸŸ ]
    (albert 'talk)
    ๐Ÿ˜ฎ : manifester     les      canyons    
    albert (๐ŸŽ‚ 3) ๐Ÿ˜ƒ [ ๐Ÿฐ ] ;; all is ok
    albert (๐ŸŽ‚ 4) ๐Ÿ‘ [ ]    
    albert (๐ŸŽ‚ 5) ๐Ÿ˜ƒ [ ]    
    albert (๐ŸŽ‚ 6) ๐Ÿ˜ฅ [ โ“ ๐Ÿ’ฉ ]    
    (albert 'clean)
    albert (๐ŸŽ‚ 6) ๐Ÿ˜ช [ ๐Ÿ’ค ]
    albert (๐ŸŽ‚ 7) ๐Ÿ˜ฐ [ ๐Ÿ’ญ ๐Ÿ’ฉ ]    
    albert (๐ŸŽ‚ 8) ๐Ÿ˜“ [ ๐Ÿ’ญ ๐Ÿ’ฉ ]    
    (for ((i 10)) (albert 'feed))
    albert (๐ŸŽ‚ 8) ๐Ÿ˜ฑ [ ๐Ÿ’ญ ๐Ÿ”๐Ÿผ๐Ÿ”๐Ÿผ๐Ÿœ๐Ÿผ๐ŸŸ๐Ÿ”๐Ÿ”๐ŸŸ ๐Ÿ’ฉ ] ;; very sick
    albert (๐ŸŽ‚ 9) ๐Ÿ˜ฑ [ โ“ ๐Ÿฐ๐Ÿฐ๐ŸŸ๐ŸŸ๐Ÿผ๐ŸŸ๐Ÿœ๐Ÿœ ๐Ÿ’ฉ๐Ÿ’ฉ ]    
    (albert 'talk)
    ๐Ÿ˜ฎ : assortir     les      dรฉchiffrages    
    albert (๐ŸŽ‚ 9) ๐Ÿ˜ฑ [ ๐Ÿผ๐Ÿผ๐ŸŸ๐ŸŸ๐Ÿœ๐Ÿ”๐Ÿผ๐Ÿฐ ๐Ÿ’ฉ๐Ÿ’ฉ ]
    albert (๐ŸŽ‚ 10) ๐Ÿ˜ก [ ๐Ÿ’ญ ๐Ÿฐ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ๐Ÿœ ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ ]  

    (for ((i 20)) (albert 'talk)) ;; can talk without getting tired
    ๐Ÿ˜ฎ : rรฉaliser     les      dรฉlassements    
    ๐Ÿ˜ฎ : ratiboiser     les      รฉtatistes    
    ๐Ÿ˜ฎ : commenter     les      diphtongues    
    ๐Ÿ˜ฎ : jurer     les      samouraรฏs    
    ๐Ÿ˜ฎ : bousculer     les      mรฉchages    
    ๐Ÿ˜ฎ : รฉpรฉpiner     les      dรฉnicotiniseurs    
    ๐Ÿ˜ฎ : tรฉmoigner     les      pรฉniches    
    ๐Ÿ˜ฎ : pateliner     les      maquereaux    
    ๐Ÿ˜ฎ : conseiller     les      diminutifs    
    ๐Ÿ˜ฎ : gratiner     les      perdreaux    
    ๐Ÿ˜ฎ : klaxonner     les      รฉlues    
    ๐Ÿ˜ฎ : ganser     les      dรฉvoltages    
    ๐Ÿ˜ฎ : rรฉconcilier     les      pixels    ;; reconciliate the pixels
    ๐Ÿ˜ฎ : rocher     les      รฉcrasรฉs    
    ๐Ÿ˜ฎ : guรชtrer     les      transgressions    
    ๐Ÿ˜ฎ : lanterner     les      pisseurs    
    ๐Ÿ˜ฎ : opรฉrer     les      rasades    
    ๐Ÿ˜ฎ : actionner     les      loukoums    
    ๐Ÿ˜ฎ : dรฉgarnir     les      artichauts    
    ๐Ÿ˜ฎ : chanfreiner     les      rajeunissements    
 
    (for ((i 14)) (albert 'feed)) ;; don't feed it too much .. it will die
    albert (๐ŸŽ‚ 10) ๐Ÿ˜‡ R.I.P ;; died at age 10
    albert (๐ŸŽ‚ 10) โŒ R.I.P    
    albert (๐ŸŽ‚ 10) ๐Ÿ‘ฝ R.I.P    
    albert (๐ŸŽ‚ 10) ๐Ÿ˜‡ R.I.P    
    albert (๐ŸŽ‚ 10) ๐Ÿ˜‡ R.I.P  
  
    (make-tamagotchi 'simon)
    simon
    simon (๐ŸŽ‚ 1) ๐Ÿ˜“ [ ๐Ÿ’ค ๐Ÿ’ฉ ]    

Forth

( current object )
0 value o
' o >body constant 'o
: >o ( o -- ) postpone o postpone >r postpone 'o postpone ! ; immediate
: o> ( -- )   postpone r> postpone 'o postpone ! ; immediate

( chibi: classes with a current object and no formal methods )
0 constant object
: subclass ( class "name" -- a )  create here swap , does> @ ;
: class ( "name" -- a )  object subclass ;
: end-class ( a -- )  drop ;
: var ( a size "name" -- a )  over dup @ >r +!
  : postpone o r> postpone literal postpone + postpone ; ;

( tamagotchi )
class tama
  cell var hunger
  cell var boredom
  cell var age
  cell var hygiene
  cell var digestion
  cell var pooped
end-class

: offset ( -- )  \ go to column #13 of current line
  s\" \e[13G" type ;

: show ( "field" -- )
  ' POSTPONE literal POSTPONE dup
  POSTPONE cr POSTPONE id. POSTPONE offset
  POSTPONE execute POSTPONE ? ;  immediate
: dump ( -- )
  show hunger  show boredom  show age  show hygiene
  cr ." pooped" offset pooped @ if ." yes" else ." no" then ;

\ these words both exit their caller on success
: -poop ( -- )
  digestion @ 1 <> ?exit  digestion off  pooped on
  cr ." tama poops!"  r> drop ;
: -hunger ( -- )
  digestion @ 0 <> ?exit  hunger ++
  cr ." tama's stomach growls"  r> drop ;

: died-from ( 'reason' f -- )
  if cr ." tama died from " type cr bye then 2drop ;
: by-boredom ( -- )  "boredom"  boredom @ 5 > died-from ;
: by-sickness ( -- ) "sickness" hygiene @ 1 < died-from ;
: by-hunger ( -- )   "hunger"   hunger @  5 > died-from ;
: by-oldness ( -- )  "age"      age @    30 > died-from ;

: sicken ( -- )  pooped @ if hygiene -- then ;
: digest ( -- )  -poop -hunger  digestion -- ;
: die ( -- )     by-boredom  by-sickness  by-hunger  by-oldness ;

( tamagotchi ops )
: spawn ( -- )
  cr ." tama is born!"
  hunger off  boredom off  age off  pooped off
  5 hygiene !  5 digestion ! ;

: wait ( -- )
  cr ." ** time passes **"
  boredom ++  age ++
  digest sicken die ;

: look ( -- )  0
  boredom @ 2 > if 1+ cr ." tama looks bored" then
  hygiene @ 5 < if 1+ cr ." tama could use a wash" then
  hunger @  0 > if 1+ cr ." tama's stomach is grumbling" then
  age @    20 > if 1+ cr ." tama is getting long in the tooth" then
  pooped @      if 1+ cr ." tama is disgusted by its own waste" then
  0= if cr ." tama looks fine" then ;

: feed ( -- )
  hunger @ 0= if cr ." tama bats the offered food away" exit then
  cr ." tama happily devours the offered food"
  hunger off  5 digestion ! ;

: clean ( -- )
  pooped @ 0= if cr ." tama is clean enough already." exit then
  cr ." You dispose of the mess."  pooped off  5 hygiene ! ;

: play ( -- )
  boredom @ 0= if cr ." tama ignores you." exit then
  cr ." tama plays with you for a while."  boredom off ;

( game mode )
\ this just permanently sets the current object
\ a more complex game would use >o ... o> to set it
create pet  tama allot
pet to o

cr .( You have a pet tamagotchi!)
cr
cr .( commands:  WAIT LOOK FEED CLEAN PLAY)
cr  ( secret commands: SPAWN DUMP )
spawn look
cr

Boredom kills tama faster than anything else.

Go

This is inspired by the EchoLisp entry but written as a terminal rather than a browser application and altered in a number of respects. In particular, it uses hard-coded word lists of transitive verbs and plural nouns rather than downloading a suitable 'free' dictionary (I couldn't find one anyway) and consequently the tamagotchi's vocabulary is somewhat limited!

package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "os"
    "strconv"
    "strings"
    "time"
)

type tamagotchi struct {
    name                   string
    age, bored, food, poop int
}

var tama tamagotchi // current tamagotchi

var verbs = []string{
    "Ask", "Ban", "Bash", "Bite", "Break", "Build",
    "Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
    "Eat", "End", "Feed", "Fill", "Force", "Grasp",
    "Gas", "Get", "Grab", "Grip", "Hoist", "House",
    "Ice", "Ink", "Join", "Kick", "Leave", "Marry",
    "Mix", "Nab", "Nail", "Open", "Press", "Quash",
    "Rub", "Run", "Save", "Snap", "Taste", "Touch",
    "Use", "Vet", "View", "Wash", "Xerox", "Yield",
}

var nouns = []string{
    "arms", "bugs", "boots", "bowls", "cabins", "cigars",
    "dogs", "eggs", "fakes", "flags", "greens", "guests",
    "hens", "hogs", "items", "jowls", "jewels", "juices",
    "kits", "logs", "lamps", "lions", "levers", "lemons",
    "maps", "mugs", "names", "nests", "nights", "nurses",
    "orbs", "owls", "pages", "posts", "quests", "quotas",
    "rats", "ribs", "roots", "rules", "salads", "sauces",
    "toys", "urns", "vines", "words", "waters", "zebras",
}

var (
    boredIcons = []rune{'๐Ÿ’ค', '๐Ÿ’ญ', 'โ“'}
    foodIcons  = []rune{'๐Ÿผ', '๐Ÿ”', '๐ŸŸ', '๐Ÿฐ', '๐Ÿœ'}
    poopIcons  = []rune{'๐Ÿ’ฉ'}
    sickIcons1 = []rune{'๐Ÿ˜„', '๐Ÿ˜ƒ', '๐Ÿ˜€', '๐Ÿ˜Š', '๐Ÿ˜Ž', '๐Ÿ‘'} // ok
    sickIcons2 = []rune{'๐Ÿ˜ช', '๐Ÿ˜ฅ', '๐Ÿ˜ฐ', '๐Ÿ˜“'} // ailing
    sickIcons3 = []rune{'๐Ÿ˜ฉ', '๐Ÿ˜ซ'} // bad
    sickIcons4 = []rune{'๐Ÿ˜ก', '๐Ÿ˜ฑ'} // very bad
    sickIcons5 = []rune{'โŒ', '๐Ÿ’€', '๐Ÿ‘ฝ', '๐Ÿ˜‡'} // dead
)

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

func abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}

// convert to string and add braces {}
func brace(runes []rune) string {
    return fmt.Sprintf("{ %s }", string(runes))
}

func create(name string) {
    tama = tamagotchi{name, 0, 0, 2, 0}
}

// alive if sickness <= 10
func alive() bool {
    if sickness() <= 10 {
        return true
    }
    return false
}

func feed() {
    tama.food++
}

// may or may not help with boredom
func play() {
    tama.bored = max(0, tama.bored-rand.Intn(2))
}

func talk() {
    verb := verbs[rand.Intn(len(verbs))]
    noun := nouns[rand.Intn(len(nouns))]
    fmt.Printf("๐Ÿ˜ฎ : %s the %s.\n", verb, noun)
    tama.bored = max(0, tama.bored-1)
}

func clean() {
    tama.poop = max(0, tama.poop-1)
}

// get older / eat food / get bored / poop
func wait() {
    tama.age++
    tama.bored += rand.Intn(2)
    tama.food = max(0, tama.food-2)
    tama.poop += rand.Intn(2)
}

// get boredom / food / poop icons
func status() string {
    if alive() {
        var b, f, p []rune
        for i := 0; i < tama.bored; i++ {
            b = append(b, boredIcons[rand.Intn(len(boredIcons))])
        }
        for i := 0; i < tama.food; i++ {
            f = append(f, foodIcons[rand.Intn(len(foodIcons))])
        }
        for i := 0; i < tama.poop; i++ {
            p = append(p, poopIcons[rand.Intn(len(poopIcons))])
        }
        return fmt.Sprintf("%s  %s  %s", brace(b), brace(f), brace(p))
    }
    return " R.I.P"
}

// too much boredom / food / poop
func sickness() int {
    // dies at age 42 at the latest
    return tama.poop + tama.bored + max(0, tama.age-32) + abs(tama.food-2)
}

// get health status from sickness level
func health() {
    s := sickness()
    var icon rune
    switch s {
    case 0, 1, 2:
        icon = sickIcons1[rand.Intn(len(sickIcons1))]
    case 3, 4:
        icon = sickIcons2[rand.Intn(len(sickIcons2))]
    case 5, 6:
        icon = sickIcons3[rand.Intn(len(sickIcons3))]
    case 7, 8, 9, 10:
        icon = sickIcons4[rand.Intn(len(sickIcons4))]
    default:
        icon = sickIcons5[rand.Intn(len(sickIcons5))]
    }
    fmt.Printf("%s (๐ŸŽ‚ %d)  %c %d  %s\n\n", tama.name, tama.age, icon, s, status())
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func blurb() {
    fmt.Println("When the '?' prompt appears, enter an action optionally")
    fmt.Println("followed by the number of repetitions from 1 to 9.")
    fmt.Println("If no repetitions are specified, one will be assumed.")
    fmt.Println("The available options are: feed, play, talk, clean or wait.\n")
}

func main() {
    rand.Seed(time.Now().UnixNano())
    fmt.Println("         TAMAGOTCHI EMULATOR")
    fmt.Println("         ===================\n")
    scanner := bufio.NewScanner(os.Stdin)
    fmt.Print("Enter the name of your tamagotchi : ")
    if ok := scanner.Scan(); !ok {
        check(scanner.Err())
    }
    name := strings.TrimSpace(strings.ToLower(scanner.Text()))
    create(name)
    fmt.Printf("\n%*s (age) health {bored} {food}  {poop}\n\n", -len(name), "name")
    health()
    blurb()
    count := 0
    for alive() {
        fmt.Print("? ")
        if ok := scanner.Scan(); !ok {
            check(scanner.Err())
        }
        input := strings.TrimSpace(strings.ToLower(scanner.Text()))
        items := strings.Split(input, " ")
        if len(items) > 2 {
            continue
        }
        action := items[0]
        if action != "feed" && action != "play" && action != "talk" &&
            action != "clean" && action != "wait" {
            continue
        }
        reps := 1
        if len(items) == 2 {
            var err error
            reps, err = strconv.Atoi(items[1])
            if err != nil {
                continue
            }
        }
        for i := 0; i < reps; i++ {
            switch action {
            case "feed":
                feed()
            case "play":
                play()
            case "talk":
                talk()
            case "clean":
                clean()
            case "wait":
                wait()
            }
            // simulate wait on every third (non-wait) action, say
            if action != "wait" {
                count++
                if count%3 == 0 {
                    wait()
                }
            }
        }
        health()
    }
}
Output:

A sample session. To keep the output to a reasonable length, the tamgotchi's demise has been hastened somewhat by overfeeding.

         TAMAGOTCHI EMULATOR
         ===================

Enter the name of your tamagotchi : jeremy

name   (age) health {bored} {food}  {poop}

jeremy (๐ŸŽ‚ 0)  ๐Ÿ˜€ 0  {  }  { ๐Ÿ”๐Ÿœ }  {  }

When the '?' prompt appears, enter an action optionally
followed by the number of repetitions from 1 to 9.
If no repetitions are specified, one will be assumed.
The available options are: feed, play, talk, clean or wait.

? feed 4
jeremy (๐ŸŽ‚ 1)  ๐Ÿ˜Ž 2  {  }  { ๐Ÿฐ๐Ÿ”๐Ÿฐ๐Ÿผ }  {  }

? wait 4
jeremy (๐ŸŽ‚ 5)  ๐Ÿ˜ฑ 7  { โ“๐Ÿ’คโ“ }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ }

? clean 2
jeremy (๐ŸŽ‚ 6)  ๐Ÿ˜ซ 6  { โ“๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค }  {  }  {  }

? talk 4
๐Ÿ˜ฎ : Nail the items.
๐Ÿ˜ฎ : Drink the toys.
๐Ÿ˜ฎ : Get the nurses.
๐Ÿ˜ฎ : Marry the rules.
jeremy (๐ŸŽ‚ 7)  ๐Ÿ˜ƒ 2  {  }  {  }  {  }

? feed 6
jeremy (๐ŸŽ‚ 9)  ๐Ÿ˜ƒ 1  {  }  { ๐Ÿผ๐Ÿฐ }  { ๐Ÿ’ฉ }

? wait 3
jeremy (๐ŸŽ‚ 12)  ๐Ÿ˜ก 7  { โ“๐Ÿ’ค }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? play 2
jeremy (๐ŸŽ‚ 13)  ๐Ÿ˜ก 8  { ๐Ÿ’ค๐Ÿ’ค }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? clean 4
jeremy (๐ŸŽ‚ 14)  ๐Ÿ˜ซ 6  { ๐Ÿ’ญโ“โ“ }  {  }  { ๐Ÿ’ฉ }

? talk 3
๐Ÿ˜ฎ : Wash the salads.
๐Ÿ˜ฎ : Drag the ribs.
๐Ÿ˜ฎ : Ink the mugs.
jeremy (๐ŸŽ‚ 15)  ๐Ÿ˜ฐ 4  {  }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ }

? feed 6 
jeremy (๐ŸŽ‚ 17)  ๐Ÿ˜ฉ 6  { โ“๐Ÿ’ญ }  { ๐ŸŸ๐Ÿœ }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? clean 4
jeremy (๐ŸŽ‚ 18)  ๐Ÿ˜ฉ 5  { ๐Ÿ’ญ๐Ÿ’ญ }  {  }  { ๐Ÿ’ฉ }

? talk 2
๐Ÿ˜ฎ : Use the sauces.
๐Ÿ˜ฎ : Touch the items.
jeremy (๐ŸŽ‚ 19)  ๐Ÿ˜“ 4  {  }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ }

? feed 8
jeremy (๐ŸŽ‚ 22)  ๐Ÿ˜ฉ 5  { โ“ }  { ๐Ÿœ๐Ÿ” }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? clean 4
jeremy (๐ŸŽ‚ 23)  ๐Ÿ˜ฅ 3  { ๐Ÿ’ค }  {  }  {  }

? wait 4
jeremy (๐ŸŽ‚ 27)  ๐Ÿ˜ก 7  { โ“๐Ÿ’ญโ“๐Ÿ’ญ }  {  }  { ๐Ÿ’ฉ }

? feed 8
jeremy (๐ŸŽ‚ 30)  ๐Ÿ˜ซ 6  { ๐Ÿ’คโ“๐Ÿ’ค๐Ÿ’คโ“ }  { ๐Ÿฐ๐Ÿฐ }  { ๐Ÿ’ฉ }

? talk 5
๐Ÿ˜ฎ : Xerox the nests.
๐Ÿ˜ฎ : Drag the quests.
๐Ÿ˜ฎ : Cut the bowls.
๐Ÿ˜ฎ : Force the cigars.
๐Ÿ˜ฎ : Mix the flags.
jeremy (๐ŸŽ‚ 31)  ๐Ÿ˜ช 4  { ๐Ÿ’ค }  {  }  { ๐Ÿ’ฉ }

? feed 8
jeremy (๐ŸŽ‚ 34)  ๐Ÿ˜ฑ 9  { ๐Ÿ’ค๐Ÿ’ญโ“ }  { ๐Ÿœ๐Ÿ”๐ŸŸ }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? clean 3
jeremy (๐ŸŽ‚ 35)  ๐Ÿ˜ก 8  { ๐Ÿ’คโ“๐Ÿ’ค๐Ÿ’ค }  { ๐Ÿผ }  {  }

? play 4
jeremy (๐ŸŽ‚ 36)  ๐Ÿ˜ก 9  { ๐Ÿ’ค๐Ÿ’ญ }  {  }  { ๐Ÿ’ฉ }

? feed 9
jeremy (๐ŸŽ‚ 39)  ๐Ÿ˜‡ 16   R.I.P

Java

This is a direct translation of the Go version. As such, the output will be similar if not identical.

The code does not use any Java 8+ features so it may function on lower versions.

package com.mt;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

class Tamagotchi {
	public String name;
	public int age,bored,food,poop;
	
}

public class TamagotchiGame {
	Tamagotchi tama;//current Tamagotchi
	Random random = new Random(); // pseudo random number generator
	
	String[] verbs = {
			"Ask", "Ban", "Bash", "Bite", "Break", "Build",
		    "Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
		    "Eat", "End", "Feed", "Fill", "Force", "Grasp",
		    "Gas", "Get", "Grab", "Grip", "Hoist", "House",
		    "Ice", "Ink", "Join", "Kick", "Leave", "Marry",
		    "Mix", "Nab", "Nail", "Open", "Press", "Quash",
		    "Rub", "Run", "Save", "Snap", "Taste", "Touch",
		    "Use", "Vet", "View", "Wash", "Xerox", "Yield",
	};
	
	String[] nouns = {
			"arms", "bugs", "boots", "bowls", "cabins", "cigars",
		    "dogs", "eggs", "fakes", "flags", "greens", "guests",
		    "hens", "hogs", "items", "jowls", "jewels", "juices",
		    "kits", "logs", "lamps", "lions", "levers", "lemons",
		    "maps", "mugs", "names", "nests", "nights", "nurses",
		    "orbs", "owls", "pages", "posts", "quests", "quotas",
		    "rats", "ribs", "roots", "rules", "salads", "sauces",
		    "toys", "urns", "vines", "words", "waters", "zebras",
	};
	
	String[] boredIcons = {"๐Ÿ’ค", "๐Ÿ’ญ", "โ“"};
	String[] foodIcons = {"๐Ÿผ", "๐Ÿ”", "๐ŸŸ", "๐Ÿฐ", "๐Ÿœ"};
	String[] poopIcons = {"๐Ÿ’ฉ"};
	String[] sickIcons1 = {"๐Ÿ˜„", "๐Ÿ˜ƒ", "๐Ÿ˜€", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿ‘"};//ok
	String[] sickIcons2 = {"๐Ÿ˜ช", "๐Ÿ˜ฅ", "๐Ÿ˜ฐ", "๐Ÿ˜“"};//ailing
	String[] sickIcons3 = {"๐Ÿ˜ฉ", "๐Ÿ˜ซ"};//bad
	String[] sickIcons4 = {"๐Ÿ˜ก", "๐Ÿ˜ฑ"};//very bad
	String[] sickIcons5 = {"โŒ", "๐Ÿ’€", "๐Ÿ‘ฝ", "๐Ÿ˜‡"};//dead
	
	String brace(String string) {
		return String.format("{ %s }", string);
	}
	
	void create(String name) {
		tama = new Tamagotchi();
		tama.name = name;
		tama.age = 0;
		tama.bored = 0;
		tama.food = 2;
		tama.poop = 0;
	}
	
	boolean alive() { // alive if sickness <= 10
		return sickness() <= 10;
	}
	
	void feed() {
		tama.food++;
	}
	
	void play() {//may or may not help with boredom
		tama.bored = Math.max(0, tama.bored - random.nextInt(2));
	}
	
	void talk() {
		String verb = verbs[random.nextInt(verbs.length)];
		String noun = nouns[random.nextInt(nouns.length)];
		System.out.printf("๐Ÿ˜ฎ : %s the %s.%n", verb, noun);
		tama.bored = Math.max(0, tama.bored - 1);
	}
	
	void clean() {
		tama.poop = Math.max(0, tama.poop - 1);
	}
	
	void idle() {//renamed from wait() due to wait being an existing method from the Object class
		tama.age++;
		tama.bored += random.nextInt(2);
		tama.food = Math.max(0, tama.food - 2);
		tama.poop += random.nextInt(2);
	}
	
	String status() {// get boredom/food/poop icons
		if(alive()) {
			StringBuilder b = new StringBuilder(),
					f = new StringBuilder(),
					p = new StringBuilder();
			for(int i = 0; i < tama.bored; i++) {
				b.append(boredIcons[random.nextInt(boredIcons.length)]);
			}
			for(int i = 0; i < tama.food; i++) {
				f.append(foodIcons[random.nextInt(foodIcons.length)]);
			}
			for(int i = 0; i < tama.poop; i++) {
				p.append(poopIcons[random.nextInt(poopIcons.length)]);
			}
			
			return String.format("%s  %s  %s", brace(b.toString()), brace(f.toString()), brace(p.toString()));
		}
		
		return " R.I.P";
	}
	
	//too much boredom/food/poop
	int sickness() {
		//dies at age 42 at the latest
		return tama.poop + tama.bored + Math.max(0, tama.age - 32) + Math.abs(tama.food - 2);
	}
	
	//get health status from sickness level
	void health() {
		int s = sickness();
		String icon;
		switch(s) {
		case 0:
		case 1:
		case 2:
			icon = sickIcons1[random.nextInt(sickIcons1.length)];
			break;
		case 3:
		case 4:
			icon = sickIcons2[random.nextInt(sickIcons2.length)];
			break;
		case 5:
		case 6:
			icon = sickIcons3[random.nextInt(sickIcons3.length)];
			break;
		case 7:
		case 8:
		case 9:
		case 10:
			icon = sickIcons4[random.nextInt(sickIcons4.length)];
			break;
		default:
			icon = sickIcons5[random.nextInt(sickIcons5.length)];
			break;
		}
		
		System.out.printf("%s (๐ŸŽ‚ %d)  %s %d  %s%n%n", tama.name, tama.age, icon, s, status());
	}
	
	void blurb() {
		System.out.println("When the '?' prompt appears, enter an action optionally");
		System.out.println("followed by the number of repetitions from 1 to 9.");
		System.out.println("If no repetitions are specified, one will be assumed.");
		System.out.println("The available options are: feed, play, talk, clean or wait.\n");
	}
	
	public static void main(String[] args) {
		TamagotchiGame game = new TamagotchiGame();
		game.random.setSeed(System.nanoTime());
		
		System.out.println("         TAMAGOTCHI EMULATOR");
		System.out.println("         ===================\n");
		
		Scanner scanner = new Scanner(System.in);
		System.out.print("Enter the name of your tamagotchi : ");
		String name = scanner.nextLine().toLowerCase().trim();
		
		game.create(name);
		System.out.printf("%n%s (age) health {bored} {food}    {poop}%n%n", "name");
		game.health();
		game.blurb();
		
		ArrayList<String> commands = new ArrayList<>(List.of("feed", "play", "talk", "clean", "wait"));
		
		int count = 0;
		while(game.alive()) {
			System.out.print("? ");
			String input = scanner.nextLine().toLowerCase().trim();
			String[] items = input.split(" ");
			if(items.length > 2) continue;
			
			String action = items[0];
			if(!commands.contains(action)) {
				continue;
			}
			
			int reps;
			if(items.length == 2) {
				reps = Integer.parseInt(items[1]);
			} else {
				reps = 1;
			}
			
			for(int i = 0; i < reps; i++) {
				switch(action) {
				case "feed":
					game.feed();
					break;
				case "play":
					game.play();
					break;
				case "talk":
					game.talk();
					break;
				case "wait":
					game.idle();
					break;
				}
				
				//simulate a wait on every third (non-wait) action
				if(!action.equals("wait")) {
					count++;
					if(count%3==0) {
						game.idle();
					}
				}
			}
			game.health();
		}
		
		scanner.close();
	}
}
Output:
         TAMAGOTCHI EMULATOR
         ===================

Enter the name of your tamagotchi : jeremy

name (age) health {bored} {food}    {poop}

jeremy (๐ŸŽ‚ 0)  ๐Ÿ˜€ 0  {  }  { ๐Ÿœ๐Ÿœ }  {  }

When the '?' prompt appears, enter an action optionally
followed by the number of repetitions from 1 to 9.
If no repetitions are specified, one will be assumed.
The available options are: feed, play, talk, clean or wait.

? feed 4
jeremy (๐ŸŽ‚ 1)  ๐Ÿ˜ฅ 3  {  }  { ๐ŸŸ๐Ÿœ๐ŸŸ๐Ÿœ }  { ๐Ÿ’ฉ }

? wait 4
jeremy (๐ŸŽ‚ 5)  ๐Ÿ˜ซ 5  { ๐Ÿ’ญ๐Ÿ’ค }  {  }  { ๐Ÿ’ฉ }

? clean 2
jeremy (๐ŸŽ‚ 6)  ๐Ÿ˜ซ 6  { ๐Ÿ’ญ๐Ÿ’ญ๐Ÿ’ญ }  {  }  { ๐Ÿ’ฉ }

? talk 4
๐Ÿ˜ฎ : Grasp the names.
๐Ÿ˜ฎ : Vet the greens.
๐Ÿ˜ฎ : Grasp the urns.
๐Ÿ˜ฎ : Dig the zebras.
jeremy (๐ŸŽ‚ 7)  ๐Ÿ˜ฐ 3  {  }  {  }  { ๐Ÿ’ฉ }

? feed 6
jeremy (๐ŸŽ‚ 9)  ๐Ÿ˜Š 2  {  }  { ๐Ÿผ๐ŸŸ }  { ๐Ÿ’ฉ๐Ÿ’ฉ }

? play 2
jeremy (๐ŸŽ‚ 10)  ๐Ÿ˜ฉ 5  {  }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

? talk
๐Ÿ˜ฎ : Touch the eggs.
jeremy (๐ŸŽ‚ 10)  ๐Ÿ˜ซ 5  {  }  {  }  { ๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ }

Julia

GUI version with the Gtk library.

using Gtk, GtkUtilities, Cairo, Images

mutable struct Pet
    species::String
    name::String
    age::Int  # days
    weight::Int
    health::Int
    hunger::Int
    happiness::Int
    Pet() = new("Dog", "Tam", 366, 3, 8, 4, 8)
end

introduce(pet) = "Hello! My name is $(pet.name) and I am your pet, a $(pet.age รท 365)-year-old $(pet.species)!"
wellbeing(pet) = "My weight is $(pet.weight), I have $(pet.health) health points and $(pet.happiness) happy points."
request(pet) = "Please look after me..."
increase_health(pet::Pet) = (pet.health += (pet.health < 8) ? 1 : 0)
decrease_health(pet::Pet) = (pet.health -= (pet.health > 2) ? 1 : 0)
increase_weight(pet) = (pet.weight += (pet.weight < 8) ? 1 : 0)
decrease_weight(pet) = (pet.weight < 3 ? decrease_health(pet) : pet.weight -= 1)
decrease_hunger(pet) = (pet.hunger -= (pet.hunger > 2) ? 1 : 0)
increase_hunger(pet) = (pet.hunger += (pet.hunger < 8) ? 1 : 0)
increase_happiness(pet) = (pet.happiness += (pet.happiness < 8) ? 1 : 0)
decrease_happiness(pet) = (pet.happiness < 3 ?  decrease_health(pet) : pet.happiness -= 1)

const pet_default_image = load("/users/wherr/documents/Julia Programs/pet_default.png")
const pet_cuddle_image = load("/users/wherr/documents/Julia Programs/pet_cuddle.png")
const pet_feeding_image = load("/users/wherr/documents/julia programs/pet_feeding.png")
const pet_catch_stick_image = load("/users/wherr/documents/julia programs/pet_catch_stick.png")
const pet_sleeping_image = load("/users/wherr/documents/julia programs/pet_sleeping.png")
const pet_tailchase_image = load("/users/wherr/documents/julia programs/pet_tailchase.png")
const pet_poop_image = load("/users/wherr/documents/julia programs/pet_poop.png")
const pet_walk_image = load("/users/wherr/documents/julia programs/pet_walk.png")
const pet_vet_image = load("/users/wherr/documents/julia programs/pet_vet.png")
const pet_sick_image = load("/users/wherr/documents/julia programs/pet_sick.png")
const pet_death_image = load("/users/wherr/documents/julia programs/pet_death.png")

function TamagotchiApp()
    poop_chance = 0.1
    old_age_end_chance = 0.2
    health_end_chance = 0.2
    waiting_time = 15
    pet = Pet()
    win = Gtk.Window(pet.name, 500, 700)
    button_yes = false
    button_no = false
    label = Gtk.Label(introduce(pet))
    canvas = Gtk.GtkCanvas()
    button1 = Gtk.Button("Yes")
    button2 = Gtk.Button("No")
    status = Gtk.Label(" ")
    vbox = Gtk.GtkBox(:v)
    bbox = Gtk.GtkBox(:h)
    push!(bbox, button1, button2, status)
    push!(vbox, label, canvas, bbox)
    push!(win, vbox)
    set_gtk_property!(vbox, :expand, true)
    set_gtk_property!(canvas, :expand, true)
    current_image = pet_default_image
    showall(win)
    info_dialog(introduce(pet))
    info_dialog(wellbeing(pet))

    @guarded draw(canvas) do widget
        ctx = getgc(canvas)
        copy!(ctx, current_image)
    end

    update_image(img) = (current_image = img; draw(canvas))

    function update_status()
        str = "    Age " * rpad(pet.age รท 365, 5) * "Weight " * rpad(pet.weight, 5) * "Hunger " *
            rpad(pet.hunger, 5) * "Happiness " * rpad(pet.happiness, 3)
        GAccessor.text(status, str)
    end

    function waitforbutton()
        button_yes, button_no = false, false
        t1 = time()
        while time() - t1 < waiting_time
            button_yes && return true
            button_no && return false
            sleep(0.2)
        end
        return false
    end

    function cuddles()
        clear_buttons()
        GAccessor.text(label, "Puppy is bored.\nDo you want to give Puppy a cuddle?")
        yesno = waitforbutton()
        if yesno
            increase_happiness(pet)
            if pet.happiness < 8
                GAccessor.text(label, "Yay! Happiness has increased to $(pet.happiness)!")
            elseif pet.happiness == 8
                GAccessor.text(label, "Yay! Happiness is at maximum of $(pet.happiness)!")
            end
            update_image(pet_cuddle_image)
        else
            decrease_happiness(pet)
            GAccessor.text(label, "Are you sure? Puppy really loves cuddles!\n" *
                "Happiness has decreased to $(pet.happiness)!")
        end
    end

    function hungry()
        GAccessor.text(label, "I'm hungry, feed me!")
        if waitforbutton()
            if pet.weight < 8
                increase_weight(pet)
                GAccessor.text(label, "Yay! nomnomnom\nWeight has increased to $(pet.weight)!")
            elseif pet.weight == 8
                GAccessor.text(label, "Yay! nomnomnom\nWeight is $(pet.weight)!")
            end
            decrease_hunger(pet)
            decrease_hunger(pet)
            poop_chance += 0.1
            update_image(pet_feeding_image)
        else
            decrease_weight(pet)
            GAccessor.text(label, "Aww, a hungry pet...\nWeight has decreased to $(pet.weight).")
        end
    end

    function play_stick()
        GAccessor.text(label, "Puppy is bored.\nWould you like to play a game with pet?")
        if waitforbutton()
            exercised = 0
            while exercised < 6
                update_image(pet_catch_stick_image)
                showall(win)
                GAccessor.text(label, "Yay! Let's play with the stick!\nCan you throw it for me?")
                throwdistance = rand(1:5)
                if throwdistance < 3
                    GAccessor.text(label, "Good throw.\nYay caught it, again, again!")
                    exercised += 2
                    sleep(2)
                else
                    GAccessor.text(label, "Big throw\nWoah, that was a long way to run!")
                    exercised += 3
                    sleep(2)
                end
            end
            increase_health(pet)
            if pet.health < 8
                GAccessor.text(label, "That's enough running around now.\n" * 
                    "Health has increased to $(pet.health)")
            else
                GAccessor.text(label, "Health is at its maximum of $(pet.health)!")
            end
            update_image(pet_default_image)
        else
            decrease_health(pet)
            GAccessor.text(label, "Health has decreased to $(pet.health).")
        end
    end

    function nap()
        GAccessor.text(label, "Would you like to put Puppy to bed?")
        if waitforbutton()
            update_image(pet_sleeping_image)
            showall(win)
            increase_health(pet)
            if pet.health < 8
                GAccessor.text(label, "Health has increased to $(pet.health)\n" *
                    "Zzzzzz...Zzzzzz...Puppy still sleeping...")
            elseif pet.health == 8
                GAccessor.text(label, "Health is at maximum of $(pet.health).\n" *
                    "Zzzzzz...Zzzzzz...Puppy sleeping...")
            end
        else
            decrease_health(pet)
            GAccessor.text(label, "Are you sure? Puppy is so sleepy!\nHealth has decreased to $(pet.health).")
        end
    end

    function chase_tail()
        GAccessor.text(label, "Puppy is bored...")
        sleep(2)
        GAccessor.text(label, "Puppy is having lots of fun chasing his tail...can't quite catch it!")
        update_image(pet_tailchase_image)
        showall(win)
        sleep(4)
        increase_happiness(pet)
        GAccessor.text(label, "Happiness is now $(pet.happiness)!")
    end

    function poop()
        update_image(pet_poop_image)
        showall(win)
        GAccessor.text(label, "Oops, Puppy dumped poop!  Clean up the feces?")
        if waitforbutton()
            increase_happiness(pet)
            GAccessor.text(label, "Puppy feels much better now.\n" *
            (pet.happiness < 8 ? "Happiness has increased to $(pet.happiness)!" :
                                "Happiness is $(pet.happiness)."))
            update_image(pet_default_image)
            showall(win)
            poop_chance -= 0.3
        else
            decrease_happiness(pet)
            GAccessor.text(label, "But not cleaning up will make Puppy sick!\n" *
                "Happiness has decreased to $(pet.happiness).")
        end
    end

    function walk()
        GAccessor.text(label, "Would Puppy like to go for a walk?")
        if waitforbutton()
            GAccessor.text(label, "Yay! Off we go...")
            increase_health(pet)
            if pet.health < 8
                GAccessor.text(label, "Health has increased to $(pet.health)!")
            elseif pet.health == 8
                GAccessor.text(label, "Health is $(pet.health).")
            end
            update_image(pet_walk_image)
        else
            decrease_health(pet)
            GAccessor.text(label, "Oh, but Puppy needs his exercise!\n " *
                "Health has decreased to $(pet.health).")
        end
    end

    function death()
        GAccessor.text(label, "We will miss our pet...")
        update_image(pet_death_image)
    end

    function vet()
        update_image(pet_sick_image)
        showall(win)
        GAccessor.text(label, "Puppy is sick! Take pet to vetenarian?")
        if waitforbutton()
            GAccessor.text(label, "Yay! We got pet medication!")
            update_image(pet_vet_image)
            showall(win)
            sleep(3)
            pet.health = 7
            pet.happiness = 4
            pet.weight = 4
            GAccessor.text(label, "Health has increased to $(pet.health)!")
        else
            decrease_health(pet)
            GAccessor.text(label, "Oh, but Puppy is getting sicker!\n" *
                "Health has decreased to $(pet.health).")
        end
    end

    function tamagotchi_loop()
        while true
            update_status()
            update_image(pet.health < 4 ? pet_sick_image : pet_default_image)
            pet.age += 1
            if (pet.age > 3653 && rand() < age_end_chance) ||
               (pet.health <= 2 && rand() < health_end_chance)
                death()
                break
            elseif pet.health < 4 && rand() < 0.3
                vet()
            elseif rand() < poop_chance && pet.hunger < 6
                poop()
            elseif rand() < 0.2 * (pet.hunger - 2)
                hungry()
            else
                rand([cuddles, hungry, play_stick, nap, walk, chase_tail])()
            end
            if (pet.weight < 3 || pet.happiness < 3) && pet.health > 4
                warn_dialog(request(pet))
                pet.health -= 1
            end
            increase_hunger(pet)
            update_status()
            showall(win)
            sleep(5)
        end
    end

    yes_clicked_callback(widget) = (button_yes = true; button_no = false)
    no_clicked_callback(widget) = (button_no = true; button_yes = false)
    clear_buttons() = (button_no = false; button_yes = false)
    id_yes = signal_connect(yes_clicked_callback, button1, "clicked")
    id_no = signal_connect(no_clicked_callback, button2, "clicked")
    condition = Condition()
    endit(window) = notify(condition)
    signal_connect(endit, win, :destroy)
    showall(win)
    tamagotchi_loop()
end

TamagotchiApp()

Nim

Translation of: Go
import random, strutils

const

  Verbs = ["Ask", "Ban", "Bash", "Bite", "Break", "Build",
           "Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
           "Eat", "End", "Feed", "Fill", "Force", "Grasp",
           "Gas", "Get", "Grab", "Grip", "Hoist", "House",
           "Ice", "Ink", "Join", "Kick", "Leave", "Marry",
           "Mix", "Nab", "Nail", "Open", "Press", "Quash",
           "Rub", "Run", "Save", "Snap", "Taste", "Touch",
           "Use", "Vet", "View", "Wash", "Xerox", "Yield"]

  Nouns = ["arms", "bugs", "boots", "bowls", "cabins", "cigars",
           "dogs", "eggs", "fakes", "flags", "greens", "guests",
           "hens", "hogs", "items", "jowls", "jewels", "juices",
           "kits", "logs", "lamps", "lions", "levers", "lemons",
           "maps", "mugs", "names", "nests", "nights", "nurses",
           "orbs", "owls", "pages", "posts", "quests", "quotas",
           "rats", "ribs", "roots", "rules", "salads", "sauces",
           "toys", "urns", "vines", "words", "waters", "zebras"]

  BoredIcons = ["๐Ÿ’ค", "๐Ÿ’ญ", "โ“"]
  FoodIcons  = ["๐Ÿผ", "๐Ÿ”", "๐ŸŸ", "๐Ÿฐ", "๐Ÿœ"]
  PoopIcons  = ["๐Ÿ’ฉ"]
  SickIcons1 = ["๐Ÿ˜„", "๐Ÿ˜ƒ", "๐Ÿ˜€", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿ‘"]   # ok
  SickIcons2 = ["๐Ÿ˜ช", "๐Ÿ˜ฅ", "๐Ÿ˜ฐ", "๐Ÿ˜“"]               # ailing
  SickIcons3 = ["๐Ÿ˜ฉ", "๐Ÿ˜ซ"]                           # bad
  SickIcons4 = ["๐Ÿ˜ก", "๐Ÿ˜ฑ"]                           # very bad
  SickIcons5 = ["โŒ", "๐Ÿ’€", "๐Ÿ‘ฝ", "๐Ÿ˜‡"]               # dead


type

  Tamagotchi = object
    name: string
    age, bored, food, poop: int

  Action {.pure.} = enum Feed = "feed", Play = "play", Talk = "talk", Clean = "clean", Wait = "wait"


func initTamagotchi(name: string): Tamagotchi =
  Tamagotchi(name: name, age: 0, bored: 0, food: 2, poop: 0)


func withBraces(s: string): string = "{ $# }" % s


proc feed(t: var Tamagotchi) =
  inc t.food


proc play(t: var Tamagotchi) =
  t.bored = max(0, t.bored - rand(1))


proc talk(t: var Tamagotchi) =
  let verb = Verbs.sample()
  let noun = Nouns.sample()
  echo "๐Ÿ˜ฎ: $1 the $2.".format(verb, noun)
  t.bored = max(0, t.bored - 1)


proc clean(t: var Tamagotchi) =
  t.poop = max(0, t.poop - 1)


proc wait(t: var Tamagotchi) =
  inc t.age
  t.bored += rand(1)
  t.food = max(0, t.food - 2)
  t.poop += rand(1)


func sickness(t: Tamagotchi): Natural =
  t.poop + t.bored + max(0, t.age - 32) + abs(t.food - 2)


func isAlive(t: Tamagotchi): bool = t.sickness() <= 10


proc status(t: Tamagotchi): string =
  if t.isAlive:
    var b, f, p: string
    for _ in 1..t.bored: b.add BoredIcons.sample()
    for _ in 1..t.food: f.add FoodIcons.sample()
    for _ in 1..t.poop: p.add PoopIcons.sample()
    result = "$1  $2  $3".format(b.withBraces, f.withBraces, p.withBraces)


proc displayHealth(t: Tamagotchi) =
  let s = t.sickness()
  let icon = case s
             of 0, 1, 2: SickIcons1.sample()
             of 3, 4: SickIcons2.sample()
             of 5, 6: SickIcons3.sample()
             of 7, 8, 9, 10: SickIcons4.sample()
             else: SickIcons5.sample()
  echo "$1 (๐ŸŽ‚ $2)  $3 $4  $5\n".format(t.name, t.age, icon, s, t.status())


proc blurb() =
  echo "When the '?' prompt appears, enter an action optionally"
  echo "followed by the number of repetitions from 1 to 9."
  echo "If no repetitions are specified, one will be assumed."
  echo "The available options are: feed, play, talk, clean or wait.\n"


randomize()
echo "         TAMAGOTCHI EMULATOR"
echo "         ===================\n"

stdout.write "Enter the name of your tamagotchi: "
stdout.flushFile()
var name = ""
while name.len == 0:
  try:
    name = stdin.readLine.strip()
  except EOFError:
    echo()
    quit "Encountered EOF. Quitting.", QuitFailure
var tama = initTamagotchi(name)
echo "\n$# (age) health {bored} {food}  {poop}\n" % "name".alignLeft(name.len)
tama.displayHealth()
blurb()

var count = 0
while tama.isAlive:
  stdout.write "? "
  stdout.flushFile()
  let input = try: stdin.readLine().strip().toLowerAscii()
              except EOFError:
                echo()
                quit "EOF encountered. Quitting.", QuitFailure
  let items = input.splitWhitespace()
  if items.len notin 1..2: continue
  let action = try: parseEnum[Action](items[0])
               except ValueError: continue
  let reps = if items.len == 2:
               try: items[1].parseInt()
               except ValueError: continue
             else: 1

  for _ in 1..reps:
    case action
    of Feed: tama.feed()
    of Play: tama.play()
    of Talk: tama.talk()
    of Clean: tama.clean()
    of Wait: tama.wait()

    # Simulate wait on every third (non-wait) action.
    if action != Wait:
      inc count
      if count mod 3 == 0:
        tama.wait()

  tama.displayHealth()
Output:

Same as Go output.

Phix

Translation of: Go – but with a dirt simple GUI and much harsher gameplay
--
-- demo/rosetta/tamagotchi.exw
-- ===========================
--
--    Gameplay is a bit harsh, almost impossible to keep it alive....
--
include pGUI.e

string name = "Fluffy",
       chat = ""
integer age = 0,
        bored = 0,
        food = 0,
        poop = 0
Ihandle stabel

constant verbs = {"Ask", "Ban", "Bash", "Bite", "Break", "Build",
                  "Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
                  "Eat", "End", "Feed", "Fill", "Force", "Grasp",
                  "Gas", "Get", "Grab", "Grip", "Hoist", "House",
                  "Ice", "Ink", "Join", "Kick", "Leave", "Marry",
                  "Mix", "Nab", "Nail", "Open", "Press", "Quash",
                  "Rub", "Run", "Save", "Snap", "Taste", "Touch",
                  "Use", "Vet", "View", "Wash", "Xerox", "Yield"},
         nouns = {"arms", "bugs", "boots", "bowls", "cabins", "cigars",
                  "dogs", "eggs", "fakes", "flags", "greens", "guests",
                  "hens", "hogs", "items", "jowls", "jewels", "juices",
                  "kits", "logs", "lamps", "lions", "levers", "lemons",
                  "maps", "mugs", "names", "nests", "nights", "nurses",
                  "orbs", "owls", "pages", "posts", "quests", "quotas",
                  "rats", "ribs", "roots", "rules", "salads", "sauces",
                  "toys", "urns", "vines", "words", "waters", "zebras"},
         boredIcons = {"๐Ÿ’ค", "๐Ÿ’ญ", "โ“"},
         foodIcons = {"๐Ÿผ", "๐Ÿ”", "๐ŸŸ", "๐Ÿฐ", "๐Ÿœ"},
         poopIcons = {"๐Ÿ’ฉ"},
         sickIcons = {{"๐Ÿ˜„", "๐Ÿ˜ƒ", "๐Ÿ˜€", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿ‘"}, // ok
                      {"๐Ÿ˜ช", "๐Ÿ˜ฅ", "๐Ÿ˜ฐ", "๐Ÿ˜“"}, // ailing
                      {"๐Ÿ˜ฉ", "๐Ÿ˜ซ"}, // bad
                      {"๐Ÿ˜ก", "๐Ÿ˜ฑ"}, // very bad
                      {"โŒ", "๐Ÿ’€", "๐Ÿ‘ฝ", "๐Ÿ˜‡"}}, // dead
        sicklevel = {1,1,1,2,2,3,3,4,4,4,4,5},
        fmt = "%s %s (๐ŸŽ‚ %d/42)  %s %d  %s"

procedure feed()
    food += 1
end procedure
 
procedure play()
    // may or may not help with boredom
    bored = max(0, bored-rand(2))
end procedure
 
procedure talk()
    string verb = verbs[rand(length(verbs))],
           noun = nouns[rand(length(nouns))]
    bored = max(0, bored-1)
    chat = verb & " the " & noun & ". "
end procedure
 
procedure clean()
    poop = max(0, poop-1)
end procedure
 
procedure wait()
    // get older / eat food / get bored / poop
    age += 1
    bored += rand(2)
    food = max(0, food-2)
    poop += rand(2)-1
end procedure

function sickness()
    // dies at age 42 at the latest
    // too much boredom / food / poop
    return poop + bored + max(0, age-32) + abs(food-2)
end function
  
function alive()
    return sickness() <= 10
end function

function randn(sequence s, integer n)
    string res = ""
    for i=1 to n do
        res &= s[rand(length(s))]
    end for
    return res
end function

procedure status()
    wait()
    // get health status from sickness level
    integer s = sickness(),
            sl = sicklevel[min(s+1,12)]
    string health = randn(sickIcons[sl],1)
    // get boredom / food / poop icons
    string state = " R.I.P"
    if alive() then
        string b = randn(boredIcons,bored),
               f = randn(foodIcons,food),
               p = randn(poopIcons,poop)
        state = sprintf("{ %s } { %s } { %s }", {b, f, p})
    end if
    IupSetStrAttribute(stabel,"TITLE",fmt,{chat,name,age,health,s,state})
    chat = ""
end procedure
 
function button_cb(Ihandle ih)
    string title = IupGetAttribute(ih,"TITLE")
    call_proc(routine_id(title),{})
    status()
    return IUP_DEFAULT
end function
constant cb_button = Icallback("button_cb")

function buttons()
    sequence b = {"feed","play","talk","clean","wait"}
    for i=1 to length(b) do
        b[i] = IupButton(b[i],cb_button)
    end for
    Ihandle res = IupHbox(b,`GAP=35x10`)
    return res
end function

IupOpen()
IupSetGlobal("UTF8MODE","YES")
stabel = IupLabel("","EXPAND=YES")
Ihandle vbox = IupVbox({stabel,buttons()},`MARGIN=5x5`),
        dlg = IupDialog(vbox,`TITLE=tamagotchi`)
IupShow(dlg)
status()
if platform()!=JS then
    IupMainLoop()
    IupClose()
end if

Objeck

GUI based Tamagotchi that sleeps at night. Not cleaning up poop makes Tamagotchi sicker faster. Implementation has associated sound effects.

use Game.SDL2;
use Collection;
use Game.Framework;

class Game {
  @gotchi : Tamagotchi;

  enum Faces {
    BORED,
    POOP,
    HUNGRY,
    HAPPY,
    OK,
    SAD,
    SLEEP
  }

  enum DayTime {
    MORNING,
    EVENING,
    NIGHT,
    DAY
  }

  @framework : GameFramework;
  @quit : Bool;

  @faces : AnimatedImageSprite;
  @time_of_day : AnimatedImageSprite;

  @action_chunk : MixChunk;
  @sleep_chunk : MixChunk;
  @eat_chunk : MixChunk;
  @play_chunk : MixChunk;
  @clean_chunk : MixChunk;

  @age_text : TextSprite;
  @age : Int;

  @wait_mins : Int;

  New(wait : Int) {
    @framework := GameFramework->New(Meta->SCREEN_WIDTH, Meta->SCREEN_HEIGHT, "Tamagotchi");
    @framework->SetClearColor(Color->New(240, 248, 255));
    @wait_mins := wait * @framework->GetFps() * 60; # minutes
        
    @faces := @framework->AddAnimatedImageSprite("media/faces.png");
    @faces->AddClip(Rect->New(0, 0, 240, 160));
    @faces->AddClip(Rect->New(240, 0, 240, 160));
    @faces->AddClip(Rect->New(480, 0, 240, 160));
    @faces->AddClip(Rect->New(720, 0, 240, 160));
    @faces->AddClip(Rect->New(960, 0, 240, 160));
    @faces->AddClip(Rect->New(1200, 0, 240, 160));
    @faces->AddClip(Rect->New(1440, 0, 240, 160));

    @time_of_day := @framework->AddAnimatedImageSprite("media/tod.png");
    @time_of_day->AddClip(Rect->New(0, 0, 48, 48));
    @time_of_day->AddClip(Rect->New(48, 0, 48, 48));
    @time_of_day->AddClip(Rect->New(96, 0, 48, 48));
    @time_of_day->AddClip(Rect->New(144, 0, 48, 48));
    @time_of_day->SetScale(0.5);

    @action_chunk := @framework->AddMixChunk("media/action.wav");
    @sleep_chunk := @framework->AddMixChunk("media/sleep.wav");
    @eat_chunk := @framework->AddMixChunk("media/eat.wav");
    @play_chunk := @framework->AddMixChunk("media/play.wav");
    @clean_chunk := @framework->AddMixChunk("media/clean.wav");

    @age_text := @framework->AddTextSprite();
    @age_text->RenderedText("Age: 0");
  }

  function : Main(args : String[]) ~ Nil {
    wait : Int;
    if(args->Size() = 1) {
      wait := args[0]->ToInt();
      if(wait = 0) {
        wait := Meta->WAIT;
      };
    }
    else {
      wait := Meta->WAIT;
    };

    game := Game->New(wait);
    game->Run();
  }

  method : Run() ~ Nil {
    leaving {
      @framework->Quit();
    };

    if(@framework->IsOk()) {
      @gotchi := Tamagotchi->New(@self);
            
      e := @framework->GetEvent();
      count := 0;
      while(<>@quit & @gotchi->IsAlive()) {
        Start();
      
        Input(e);
        if(count = @gotchi->GetWait()) {
          @gotchi->Update();
          count := 0;
        };
        Draw();
        count += 1;

        End();
      };
    }
    else {
      "--- Error Initializing Game Environment ---"->ErrorLine();
      return;
    };
  }

  method : public : GetWait() ~ Int {
    return @wait_mins;
  }

  method : public : ActionSound() ~ Nil {
    @action_chunk->PlayChannel(-1, 0);
  }

  method : public : SleepSound() ~ Nil {
    @sleep_chunk->PlayChannel(-1, 0);
  }

  method : public : EatSound() ~ Nil {
    @eat_chunk->PlayChannel(-1, 0);
  }

  method : public : PlaySound() ~ Nil {
    @play_chunk->PlayChannel(-1, 0);
  }

  method : public : CleanSound() ~ Nil {
    @clean_chunk->PlayChannel(-1, 0);
  }

  method : Input(e : Event) ~ Nil {
    # process input
    while(e->Poll() <> 0) {
      if(e->GetType() = EventType->SDL_QUIT) {
        @quit := true;
      }
      else if(e->GetType() = EventType->SDL_KEYDOWN & e->GetKey()->GetRepeat() = 0) {
        select(e->GetKey()->GetKeysym()->GetScancode()) {
          label Scancode->SDL_SCANCODE_F: {
            @gotchi->Input('f');
          }

          label Scancode->SDL_SCANCODE_P: {
            @gotchi->Input('p');
          }

          label Scancode->SDL_SCANCODE_C: {
            @gotchi->Input('c');
          }
        };
      };
    };
  }

  method : public : Draw() ~ Nil {
    action := @gotchi->GetAction();
    neglect := @gotchi->GetNeglect();
    
    if(@gotchi->GetState() = Tamagotchi->States->SLEEP) {
      @faces->Render(0, 40, Faces->SLEEP);
    }  
    else if(action) {
      select(@gotchi->GetState()) {
        label Tamagotchi->States->HUNGRY: {
          @faces->Render(0, 40, Faces->HUNGRY);
        }

        label Tamagotchi->States->BORED: {
          @faces->Render(0, 40, Faces->BORED);
        }

        label Tamagotchi->States->POOP: {
          @faces->Render(0, 40, Faces->POOP);
        }
      };
    }
    else if(neglect < 1.0) {
      @faces->Render(0, 40, Faces->HAPPY);
    }
    else if(neglect < 2.0) {
      @faces->Render(0, 40, Faces->OK);
    }
    else {
      @faces->Render(0, 40, Faces->SAD);
    };

    age := @gotchi->GetAge();
    buffer := "Age: ";
    buffer += age;
    @age_text->RenderedText(buffer);
    @age_text->Render(10, 10);

    hour := @gotchi->GetHour();
    if(hour >= 6 & hour <= 10) {
      @time_of_day->Render(208, 10, DayTime->MORNING);
    }
    else if(hour >= 10 & hour <= 18) {
      @time_of_day->Render(208, 10, DayTime->DAY);
    }
    else if(hour >= 18 & hour <= 20) {
      @time_of_day->Render(208, 10, DayTime->EVENING);
    }
    else {
      @time_of_day->Render(208, 10, DayTime->NIGHT);
    };
  }

  method : Start() ~ Nil {
    @framework->FrameStart();
    @framework->Clear();
  }

  method : End() ~ Nil {
    @framework->Show();
    @framework->FrameEnd();
  }
}

class Tamagotchi  {
  @state : Int;
  @age : Int;
  @hour : Int;
  @neglect : Float;
  @game : Game;
  @action : Bool;
  @wait_mins : Int;

  enum States {
    HUNGRY, 
    BORED,
    POOP,
    SLEEP
  }

  New(game : Game) {
    @game := game;
    @hour := Int->Random(24);
    Update();
  }

  method : public : GetHour() ~ Int {
    return @hour;
  }

  method : public : GetWait() ~ Int {
    return @wait_mins;
  }

  method : public : GetAge() ~ Int {
    return @age;
  }

  method : public : GetAction() ~ Bool {
    return @action;
  }

  method : public : GetState() ~ Int {  
    return @state;
  }

  method : public : GetNeglect() ~ Float {  
    return @neglect;
  }

  method : public : Update() ~ Nil {
    NextState();
    NextHour();  
  }

  method : public : IsAlive() ~ Bool {
    return @age < 4 & @neglect < 3.0;
  }

  method : public : Input(action : Char) ~ Nil {
    select(action) {
      label 'f': {
        if(@state = States->HUNGRY) {
          @neglect -= .6;
          @game->EatSound();
        };
        @action := false;
      }

      label 'p': {
        if(@state = States->BORED) {
          @neglect -= .35;
          @game->PlaySound();
        };
        @action := false;
      }

      label 'c': {
        if(@state = States->POOP) {
          @neglect -= .85;
          @game->CleanSound();
        };
        @action := false;
      }
    };
  }

  method : NextState() ~ Nil {
    @state := Int->Random(States->SLEEP);
    if(<>IsAwake() | @state = States->SLEEP) {
      @state := States->SLEEP;
      @neglect -= .1;
      @action := false;

      @game->SleepSound();
    }
    else {
      select(@state) {
        label States->HUNGRY: {
          @neglect += .5;
          @action := true;
        }

        label States->BORED: {
          @neglect += .25;
          @action := true;
        }

        label States->POOP: {
          @neglect += .75;
          @action := true;
        }
      };

      @game->ActionSound();
    };

    if(@neglect < 0.0) {
      @neglect := 0.0;
    };
    # "hour={$@hour}, neglect={$@neglect}"->PrintLine();
  }

  method : IsAwake() ~ Bool {
    return @hour > 7 & @hour < 23;
  }

  method : NextHour() ~ Nil {
    @hour += 1;
    if(@hour = 24) {
      @hour := 0;
      @age += 1;
    };
    wait := @game->GetWait();
    @wait_mins := Int->Random(wait - wait / 3, wait + wait / 3);
  }
}

consts Meta {
  SCREEN_WIDTH := 240,
  SCREEN_HEIGHT := 200,
  WAIT := 5
}

V (Vlang)

Translation of: go
import os
import strconv
import rand
import rand.seed
 
struct Tamagotchi {
    name string
mut:
    age int
bored int
food int
poop int
}

const (
verbs = [
"Ask", "Ban", "Bash", "Bite", "Break", "Build",
"Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
"Eat", "End", "Feed", "Fill", "Force", "Grasp",
"Gas", "Get", "Grab", "Grip", "Hoist", "House",
"Ice", "Ink", "Join", "Kick", "Leave", "Marry",
"Mix", "Nab", "Nail", "Open", "Press", "Quash",
"Rub", "Run", "Save", "Snap", "Taste", "Touch",
"Use", "Vet", "View", "Wash", "Xerox", "Yield",
]
 
nouns = [
"arms", "bugs", "boots", "bowls", "cabins", "cigars",
"dogs", "eggs", "fakes", "flags", "greens", "guests",
"hens", "hogs", "items", "jowls", "jewels", "juices",
"kits", "logs", "lamps", "lions", "levers", "lemons",
"maps", "mugs", "names", "nests", "nights", "nurses",
"orbs", "owls", "pages", "posts", "quests", "quotas",
"rats", "ribs", "roots", "rules", "salads", "sauces",
"toys", "urns", "vines", "words", "waters", "zebras",
]

    bored_icons = [`๐Ÿ’ค`, `๐Ÿ’ญ`, `โ“`]
    food_icons  = [`๐Ÿผ`, `๐Ÿ”`, `๐ŸŸ`, `๐Ÿฐ`, `๐Ÿœ`]
    poop_icons  = [`๐Ÿ’ฉ`]
    sick__icons1 = [`๐Ÿ˜„`, `๐Ÿ˜ƒ`, `๐Ÿ˜€`, `๐Ÿ˜Š`, `๐Ÿ˜Ž`, `๐Ÿ‘`] // ok
    sick__icons2 = [`๐Ÿ˜ช`, `๐Ÿ˜ฅ`, `๐Ÿ˜ฐ`, `๐Ÿ˜“`] // ailing
    sick__icons3 = [`๐Ÿ˜ฉ`, `๐Ÿ˜ซ`] // bad
    sick__icons4 = [`๐Ÿ˜ก`, `๐Ÿ˜ฑ`] // very bad
    sick__icons5 = [`โŒ`, `๐Ÿ’€`, `๐Ÿ‘ฝ`, `๐Ÿ˜‡`] // dead
)
 
fn max(x int, y int) int {
    if x > y {
        return x
    }
    return y
}
 
fn abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}
 
// convert to string and add braces {}
fn brace(runes []rune) string {
    return '{ ${runes.string()} }'
}
 
fn create(name string) Tamagotchi {
    return Tamagotchi{name, 0, 0, 2, 0}
}
 
// alive if sickness <= 10
fn (tama Tamagotchi) alive() bool {
    if tama.sickness() <= 10 {
        return true
    }
    return false
}
 
fn (mut tama Tamagotchi) feed() {
    tama.food++
}
 
// may or may not help with boredom
fn (mut tama Tamagotchi) play() {
    tama.bored = max(0, tama.bored-rand.intn(2) or {1})
}

fn (mut tama Tamagotchi) talk() {
    verb := verbs[rand.intn(verbs.len) or {0}]
    noun := nouns[rand.intn(nouns.len) or {0}]
    println("๐Ÿ˜ฎ : $verb the ${noun}.")
    tama.bored = max(0, tama.bored-1)
}
 
fn (mut tama Tamagotchi) clean() {
    tama.poop = max(0, tama.poop-1)
}
 
// get older / eat food / get bored / poop
fn (mut tama Tamagotchi) wait() {
    tama.age++
    tama.bored += rand.intn(2) or {1}
    tama.food = max(0, tama.food-2)
    tama.poop += rand.intn(2) or {1}
}
 
// get boredom / food / poop _icons
fn (tama Tamagotchi) status() string {
    if tama.alive() {
        mut b := []rune{}
mut f := []rune{}
mut p := []rune{}
        for i := 0; i < tama.bored; i++ {
            b << bored_icons[rand.intn(bored_icons.len) or {0}]
        }
        for i := 0; i < tama.food; i++ {
            f << food_icons[rand.intn(food_icons.len) or {0}]
        }
        for i := 0; i < tama.poop; i++ {
            p << poop_icons[rand.intn(poop_icons.len) or {0}]
        }
        return "${brace(b)}  ${brace(f)}  ${brace(p)}"
    }
    return " R.I.P"
}
 
// too much boredom / food / poop
fn (tama Tamagotchi) sickness() int {
    // dies at age 42 at the latest
    return tama.poop + tama.bored + max(0, tama.age-32) + abs(tama.food-2)
}
 
// get health status from sickness level
fn (tama Tamagotchi) health() {
    s := tama.sickness()
    mut icon := `a`
    if s in [0,1,2]{
        icon = sick__icons1[rand.intn(sick__icons1.len) or {0}]
} else if s in [3,4] {
        icon = sick__icons2[rand.intn(sick__icons2.len) or {0}]
} else if s in [5, 6] {
        icon = sick__icons3[rand.intn(sick__icons3.len) or {0}]
} else if s in [7, 8, 9, 10] {
        icon = sick__icons4[rand.intn(sick__icons4.len) or {0}]
} else {
        icon = sick__icons5[rand.intn(sick__icons5.len) or {0}]
    }
    println("$tama.name (๐ŸŽ‚ $tama.age)  $icon $s  ${tama.status()}\n")
}
 
fn blurb() {
    println("When the '?' prompt appears, enter an action optionally")
    println("followed by the number of repetitions from 1 to 9.")
    println("If no repetitions are specified, one will be assumed.")
    println("The available options are: feed, play, talk, clean or wait.\n")
}
 
fn main() {
    rand.seed(seed.time_seed_array(2))
    println("         TAMAGOTCHI EMULATOR")
    println("         ===================\n")
    name := os.input("Enter the name of your tamagotchi : ")
    mut tama := create(name)
    println("\nname (age) health {bored} {food}  {poop}\n")
    tama.health()
    blurb()
    mut count := 0
    for tama.alive() {
        input := os.input("? ")
        items := input.split(" ")
        if items.len > 2 {
            continue
        }
        action := items[0]
        if action != "feed" && action != "play" && action != "talk" &&
            action != "clean" && action != "wait" {
            continue
        }
        mut reps := 1
        if items.len == 2 {
            //var err error
            reps = strconv.atoi(items[1]) or {break}
        }
        for _ in 0..reps {
            match action {
                "feed" {
                    tama.feed()
                }
                "play" {
                    tama.play()
                }
                "talk" {
                    tama.talk()
                }
               "clean" {
                   tama.clean()
                }
                else {
                   tama.wait()
                }
            }
            // simulate wait on every third (non-wait) action, say
            if action != "wait" {
                count++
                if count%3 == 0 {
                    tama.wait()
                }
            }
        }
        tama.health()
    }
}

Wren

Translation of: Go
Library: Wren-dynamic
Library: Wren-fmt
Library: Wren-ioutil
Library: Wren-str
import "./dynamic" for Struct
import "random" for Random
import "./fmt" for Fmt
import "./ioutil" for Input
import "./str" for Str

var fields = ["name", "age", "bored", "food", "poop"]
var Tamagotchi = Struct.create("Tamagotchi", fields)

var tama  // current Tamagotchi

var rand = Random.new()

var verbs = [
    "Ask", "Ban", "Bash", "Bite", "Break", "Build",
    "Cut", "Dig", "Drag", "Drop", "Drink", "Enjoy",
    "Eat", "End", "Feed", "Fill", "Force", "Grasp",
    "Gas", "Get", "Grab", "Grip", "Hoist", "House",
    "Ice", "Ink", "Join", "Kick", "Leave", "Marry",
    "Mix", "Nab", "Nail", "Open", "Press", "Quash",
    "Rub", "Run", "Save", "Snap", "Taste", "Touch",
    "Use", "Vet", "View", "Wash", "Xerox", "Yield"
]

var nouns = [
    "arms", "bugs", "boots", "bowls", "cabins", "cigars",
    "dogs", "eggs", "fakes", "flags", "greens", "guests",
    "hens", "hogs", "items", "jowls", "jewels", "juices",
    "kits", "logs", "lamps", "lions", "levers", "lemons",
    "maps", "mugs", "names", "nests", "nights", "nurses",
    "orbs", "owls", "pages", "posts", "quests", "quotas",
    "rats", "ribs", "roots", "rules", "salads", "sauces",
    "toys", "urns", "vines", "words", "waters", "zebras"
]

var boredIcons = ["๐Ÿ’ค", "๐Ÿ’ญ", "โ“"]
var foodIcons  = ["๐Ÿผ", "๐Ÿ”", "๐ŸŸ", "๐Ÿฐ", "๐Ÿœ"]
var poopIcons  = ["๐Ÿ’ฉ"]
var sickIcons1 = ["๐Ÿ˜„", "๐Ÿ˜ƒ", "๐Ÿ˜€", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿ‘"] // ok
var sickIcons2 = ["๐Ÿ˜ช", "๐Ÿ˜ฅ", "๐Ÿ˜ฐ", "๐Ÿ˜“"] // ailing
var sickIcons3 = ["๐Ÿ˜ฉ", "๐Ÿ˜ซ"] // bad
var sickIcons4 = ["๐Ÿ˜ก", "๐Ÿ˜ฑ"] // very bad
var sickIcons5 = ["โŒ", "๐Ÿ’€", "๐Ÿ‘ฝ", "๐Ÿ˜‡"] // dead

// convert to string and add braces {}
var brace = Fn.new { |chars| "{" + chars.join() + "}" }

var create = Fn.new { |name| tama = Tamagotchi.new(name, 0, 0, 2, 0) }

// too much boredom / food / poop
var sickness = Fn.new {
    // dies at age 42 at the latest
    return tama.poop + tama.bored + 0.max(tama.age-32) + (tama.food-2).abs
}

// alive if sickness <= 10
var alive = Fn.new { sickness.call() <= 10 }

var feed = Fn.new { tama.food = tama.food + 1 }

// may or may not help with boredom
var play = Fn.new { tama.bored = 0.max(tama.bored-rand.int(2)) }

var talk = Fn.new {
    var verb = verbs[rand.int(verbs.count)]
    var noun = nouns[rand.int(nouns.count)]
    System.print("๐Ÿ˜ฎ : %(verb) the %(noun).")
    tama.bored = 0.max(tama.bored-1)
}

var clean = Fn.new { tama.poop = 0.max(tama.poop-1) }

// get older / eat food / get bored / poop
var wait = Fn.new {
    tama.age = tama.age + 1
    tama.bored = tama.bored + rand.int(2)
    tama.food = 0.max(tama.food-2)
    tama.poop = tama.poop + rand.int(2)
}

// get boredom / food / poop icons
var status = Fn.new {
    if (alive.call()) {
        var b = []
        var f = []
        var p = []
        for (i in 0...tama.bored) {
            b.add(boredIcons[rand.int(boredIcons.count)])
        }
        for (i in 0...tama.food) {
            f.add(foodIcons[rand.int(foodIcons.count)])
        }
        for (i in 0...tama.poop) {
            p.add(poopIcons[rand.int(poopIcons.count)])
        }
        return Fmt.swrite("$s  $s  $s", brace.call(b), brace.call(f),  brace.call(p))
    }
    return " R.I.P"
}

// get health status from sickness level
var health = Fn.new {
    var s = sickness.call()
    var icon
    if (s == 0 || s == 1 || s == 2) {
        icon = sickIcons1[rand.int(sickIcons1.count)]
    } else if (s == 3 || s == 4) {
        icon = sickIcons2[rand.int(sickIcons2.count)]
    } else if (s == 5 || s == 6) {
        icon = sickIcons3[rand.int(sickIcons3.count)]
    } else if (s == 7 || s == 8 || s ==  9 || s == 10) {
        icon = sickIcons4[rand.int(sickIcons4.count)]
    } else {
        icon = sickIcons5[rand.int(sickIcons5.count)]
    }
    Fmt.print("$s (๐ŸŽ‚ $d)  $s $d  $s\n", tama.name, tama.age, icon, s, status.call())
}

var blurb = Fn.new {
    System.print("When the '?' prompt appears, enter an action optionally")
    System.print("followed by the number of repetitions from 1 to 9.")
    System.print("If no repetitions are specified, one will be assumed.")
    System.print("The available options are: feed, play, talk, clean or wait.\n")
}

System.print("         TAMAGOTCHI EMULATOR")
System.print("         ===================\n")
var name = Input.text("Enter the name of your tamagotchi : ", 1)
name = Str.lower(name.trim())
create.call(name)
Fmt.print("\n$*s (age) health {bored} {food}  {poop}\n", -name.count, "name")
health.call()
blurb.call()
var count = 0
while (alive.call()) {
    var input = Str.lower(Input.text("? ", 1).trim())
    var items = input.split(" ").where { |s| s != "" }.toList
    if (items.count > 2) continue
    var action = items[0]
    if (action != "feed" && action != "play" && action != "talk" &&
        action != "clean" && action != "wait") continue
    var reps = 1
    if (items.count == 2) reps = Num.fromString(items[1])
    for (i in 0...reps) {
        if (action == "feed") {
            feed.call()
        } else if (action == "play") {
            play.call()
        } else if (action == "talk") {
            talk.call()
        } else if (action == "clean") {
            clean.call()
        } else if (action == "wait") {
            wait.call()
        }
        // simulate wait on every third (non-wait) action, say
        if (action != "wait") {
            count= count + 1
            if (count%3 == 0) wait.call()
        }
    }
    health.call()
}
Output:

Sample game - a bit reckless to keep it short.

         TAMAGOTCHI EMULATOR
         ===================

Enter the name of your tamagotchi : marcus

name   (age) health {bored} {food}  {poop}

marcus (๐ŸŽ‚ 0)  ๐Ÿ˜€ 0  {}  {๐Ÿœ๐Ÿœ}  {}

When the '?' prompt appears, enter an action optionally
followed by the number of repetitions from 1 to 9.
If no repetitions are specified, one will be assumed.
The available options are: feed, play, talk, clean or wait.

? feed 6
marcus (๐ŸŽ‚ 2)  ๐Ÿ˜ฅ 4  {๐Ÿ’ญ}  {๐Ÿœ๐ŸŸ๐Ÿผ๐ŸŸ}  {๐Ÿ’ฉ}

? talk 3
๐Ÿ˜ฎ : End the dogs.
๐Ÿ˜ฎ : Drink the roots.
๐Ÿ˜ฎ : Press the logs.
marcus (๐ŸŽ‚ 3)  ๐Ÿ˜Ž 1  {}  {๐ŸŸ๐Ÿœ}  {๐Ÿ’ฉ}

? feed 6
marcus (๐ŸŽ‚ 5)  ๐Ÿ˜ฉ 5  {โ“}  {๐Ÿœ๐Ÿœ๐Ÿฐ๐Ÿ”}  {๐Ÿ’ฉ๐Ÿ’ฉ}

? clean 2
marcus (๐ŸŽ‚ 5)  ๐Ÿ˜ฐ 3  {๐Ÿ’ค}  {๐Ÿผ๐Ÿœ๐ŸŸ๐Ÿ”}  {}

? play 4
marcus (๐ŸŽ‚ 7)  ๐Ÿ˜ซ 5  {๐Ÿ’ญ๐Ÿ’ญ๐Ÿ’ญ}  {}  {}

? feed 6
marcus (๐ŸŽ‚ 9)  ๐Ÿ˜“ 4  {๐Ÿ’คโ“โ“๐Ÿ’ญ}  {๐Ÿœ๐Ÿœ}  {}

? wait 2
marcus (๐ŸŽ‚ 11)  ๐Ÿ˜ฑ 8  {โ“๐Ÿ’ค๐Ÿ’ญ๐Ÿ’ญโ“}  {}  {๐Ÿ’ฉ}

? feed 6
marcus (๐ŸŽ‚ 13)  ๐Ÿ˜ฑ 9  {๐Ÿ’ค๐Ÿ’คโ“๐Ÿ’ญ๐Ÿ’ญโ“}  {๐Ÿผ๐Ÿฐ}  {๐Ÿ’ฉ๐Ÿ’ฉ๐Ÿ’ฉ}

? clean 3
marcus (๐ŸŽ‚ 14)  ๐Ÿ˜ก 9  {โ“๐Ÿ’คโ“โ“๐Ÿ’ญ๐Ÿ’ค}  {}  {๐Ÿ’ฉ}

? talk 2
๐Ÿ˜ฎ : Feed the rats.
๐Ÿ˜ฎ : Save the items.
marcus (๐ŸŽ‚ 14)  ๐Ÿ˜ก 7  {โ“๐Ÿ’ค๐Ÿ’ญโ“}  {}  {๐Ÿ’ฉ}

? wait 2
marcus (๐ŸŽ‚ 16)  ๐Ÿ˜ฑ 9  {๐Ÿ’ญ๐Ÿ’ญ๐Ÿ’คโ“๐Ÿ’ญ}  {}  {๐Ÿ’ฉ๐Ÿ’ฉ}

? clean 2
marcus (๐ŸŽ‚ 17)  ๐Ÿ˜ฑ 8  {๐Ÿ’ญโ“๐Ÿ’ญ๐Ÿ’คโ“๐Ÿ’ญ}  {}  {}

? feed 6
marcus (๐ŸŽ‚ 19)  ๐Ÿ˜ก 9  {๐Ÿ’ค๐Ÿ’ค๐Ÿ’ญ๐Ÿ’ญ๐Ÿ’ญ๐Ÿ’ญโ“โ“}  {๐Ÿฐ๐Ÿ”}  {๐Ÿ’ฉ}

? play 5
marcus (๐ŸŽ‚ 21)  ๐Ÿ‘ฝ 12   R.I.P