Tamagotchi emulator: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 13: Line 13:


But, above of all, have fun!
But, above of all, have fun!
=={{header|Common Lisp}}==

DRAFT
DRAFT


Line 21: Line 21:


<pre>while alive do
<pre>while alive do
case event of
case event of
feed : need (feed -3)
feed : need (feed -3)
wash : need (wash -9)
wash : need (wash -9)
play : need (play -5)
play : need (play -5)
cure : sick = no
cure : sick = no
when new turn do
when new turn do
condition
condition
age > 77 : rip
age > 77 : rip
sick w/ pr = 0.33 : rip
sick w/ pr = 0.33 : rip
feed + wash + play > 24 w/ pr = 0.5 : sick = yes
feed + wash + play > 24 w/ pr = 0.5 : sick = yes
need (feed +9)
need (feed +9)
need (wash +5)
need (wash +5)
need (play +3)
need (play +3)


need : action, delta -> action + delta + random (2)</pre>
need : action, delta -> action + delta + random (2)</pre>

Revision as of 20:00, 17 July 2022

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!

Common Lisp

DRAFT

1. Score

Variables feed, wash and play belong to the interval [0..9]. The score calculation rules are as follows :

while alive do
  case event of
    feed : need (feed -3)
    wash : need (wash -9)
    play : need (play -5)
    cure : sick = no
  when new turn do
    condition
      age > 77 : rip
      sick w/ pr = 0.33 : rip
      feed + wash + play > 24 w/ pr = 0.5 : sick = yes
    need (feed +9)
    need (wash +5)
    need (play +3)

need : action, delta -> action + delta + random (2)

2. Program

A very simple program.

<lang lisp>; 22.07.17

(defconstant +length-of-day+ 60) ; seconds

(defmacro need (action delta &optional emoji &key view)

`(progn
   (if (plusp ,delta)
     (setf ,action (min (+ ,action ,delta (random 2)) 9))
     (setf ,action (max (+ ,action ,delta (random 2)) 0)))
   (when ,view
     (format t "🤖🪄 ⤻ 😀 ✨~a✨ ⤻ 🎰 ~a~%" ,emoji ,action))))

(defun yokai ()

 (let ((feed 4) (wash 4) (play 4) (age 0) (sick "no") time rip)
   (setf time (get-universal-time))
   (write-line "🤖 Booting Yōkai... done.")    
   (write-string "🤖 Feed, wash, play, cure, show ? ")
   (loop until rip do
     (when (listen)
       (case (read-from-string (read-line) nil)
         (feed (need feed -3 "🍼" :view t))
         (wash (need wash -9 "🛁" :view t))
         (play (need play -5 "🕹️" :view t))
         (cure (setf sick "no"))
         (show (format t "🍼 ~a 🛁 ~a 🕹️ ~a 🌡️ ~a~%" feed wash play sick)))
       (format t "yōkai (~a y) > " age))
     (when (> (get-universal-time) (+ time +length-of-day+))
       (setf time (get-universal-time))
       (incf age)
       (cond ((> age 77)
         (setf rip "🗓️"))
         ((and (string= sick "yes") (zerop (random 2)))
         (setf rip "🚑"))
         ((and (> (+ feed wash play) 24) (zerop (random 3)))
         (setf sick "yes")))
       (need feed +9)
       (need wash +5)
       (need play +3))
     (sleep 1))
 (format t "~%🎃 Rest in peace Yōkai ~a~%" rip)))</lang>

3. Execution

Output:
(yokai)
🤖 Booting Yōkai... done.
🤖 Feed, wash, play, cure, show ? show
🍼 5 🛁 5 🕹️ 5 🌡️ no
yōkai (0 y) > play
🤖🪄 ⤻ 😀 ✨🕹️✨ ⤻ 🎰 4
...
🎃 Rest in peace Yōkai 🚑

4. Script engine

An APL style script engine.

4.1 Instruction set

Symbol:  Description:         Stack:      Flag N:
?        Probabilistic event  p --        w
∈        Membership           a b x --    w
→        Unconditional jump   adr --      -
↑        Jump if true         adr --      r
↓        Jump if false        adr --      r
∆        Call routine         key --      -
∇        Return from routine  -- n        -
○        Any                  lst -- elt  -
⌈        Load variable        var -- n    -
⌊        Save variable        n var --    -
⌷        Display              --          -
⍈        Whitespace           --          -
⍗        Newline              --          -

4.2 Code

¯\_(ツ)_/¯ Soon

4.3 Examples

<lang lisp>(defconstant +dialogue+

'((shazam . ("🪄🎩" ⌷ ⍈ ("shazam !" "hocus pocus !") ○ ⌷))
    (word . (("Ga" "Bu" "Zo" "Meu") ○ ⌷))
   (blank . (33 ? 1 ↓ ⍈))
    (talk . ("🐦🗯️" ⌷ ⍈ word ∆ blank ∆ word ∆ blank ∆ word ∆))))</lang>
Output:
;; Random selection (○)

(strip +dialogue+ 'shazam)
🪄🎩 shazam !
(strip +dialogue+ 'shazam)
🪄🎩 hocus pocus !

;; Routine call (∆)

(strip +dialogue+ 'talk)
🐦🗯️ Meuzo Bu

¯\_(ツ)_/¯ More soon


That's all Folks !

cyril nocton (cyril.nocton@gmail.com)

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). <lang scheme>

(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)

</lang>

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

<lang 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 </lang>

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! <lang go>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()
   }

}</lang>

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

Julia

GUI version with the Gtk library. <lang julia>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() </lang>

Nim

Translation of: Go

<lang Nim>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()</lang>
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.

<lang objeck>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

} </lang>

Vlang

Translation of: go

<lang 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()
   }

}</lang>

Wren

Translation of: Go
Library: Wren-dynamic
Library: Wren-fmt
Library: Wren-ioutil
Library: Wren-str

<lang ecmascript>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()

}</lang>

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