Tamagotchi emulator: Difference between revisions
m (typo in markup) |
m (opening dialogs) |
||
Line 658: | Line 658: | ||
end |
end |
||
introduce(pet) = "Hello! My name is $(pet.name) and I am your pet, a $(pet.age ÷ |
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." |
wellbeing(pet) = "My weight is $(pet.weight), I have $(pet.health) health points and $(pet.happiness) happy points." |
||
request(pet) = "Please look after me..." |
request(pet) = "Please look after me..." |
||
Line 664: | Line 664: | ||
decrease_health(pet::Pet) = (pet.health -= (pet.health > 2) ? 1 : 0) |
decrease_health(pet::Pet) = (pet.health -= (pet.health > 2) ? 1 : 0) |
||
increase_weight(pet) = (pet.weight += (pet.weight < 8) ? 1 : 0) |
increase_weight(pet) = (pet.weight += (pet.weight < 8) ? 1 : 0) |
||
decrease_weight(pet) = (pet.weight |
decrease_weight(pet) = (pet.weight < 3 ? decrease_health(pet) : pet.weight -= 1) |
||
decrease_hunger(pet) = (pet.hunger -= (pet.hunger > 2) ? 1 : 0) |
decrease_hunger(pet) = (pet.hunger -= (pet.hunger > 2) ? 1 : 0) |
||
increase_hunger(pet) = (pet.hunger += (pet.hunger < 8) ? 1 : 0) |
increase_hunger(pet) = (pet.hunger += (pet.hunger < 8) ? 1 : 0) |
||
increase_happiness(pet) = (pet.happiness += (pet.happiness < 8) ? 1 : 0) |
increase_happiness(pet) = (pet.happiness += (pet.happiness < 8) ? 1 : 0) |
||
decrease_happiness(pet) = (pet.happiness |
decrease_happiness(pet) = (pet.happiness < 3 ? decrease_health(pet) : pet.happiness -= 1) |
||
const pet_default_image = load("pet_default.png") |
const pet_default_image = load("/users/wherr/documents/Julia Programs/pet_default.png") |
||
const pet_cuddle_image = load("pet_cuddle.png") |
const pet_cuddle_image = load("/users/wherr/documents/Julia Programs/pet_cuddle.png") |
||
const pet_feeding_image = load("pet_feeding.png") |
const pet_feeding_image = load("/users/wherr/documents/julia programs/pet_feeding.png") |
||
const pet_catch_stick_image = load("pet_catch_stick.png") |
const pet_catch_stick_image = load("/users/wherr/documents/julia programs/pet_catch_stick.png") |
||
const pet_sleeping_image = load("pet_sleeping.png") |
const pet_sleeping_image = load("/users/wherr/documents/julia programs/pet_sleeping.png") |
||
const pet_tailchase_image = load("pet_tailchase.png") |
const pet_tailchase_image = load("/users/wherr/documents/julia programs/pet_tailchase.png") |
||
const pet_poop_image = load("pet_poop.png") |
const pet_poop_image = load("/users/wherr/documents/julia programs/pet_poop.png") |
||
const pet_walk_image = load("pet_walk.png") |
const pet_walk_image = load("/users/wherr/documents/julia programs/pet_walk.png") |
||
const pet_vet_image = load("pet_vet.png") |
const pet_vet_image = load("/users/wherr/documents/julia programs/pet_vet.png") |
||
const pet_sick_image = load("pet_sick.png") |
const pet_sick_image = load("/users/wherr/documents/julia programs/pet_sick.png") |
||
const pet_death_image = load("pet_death.png") |
const pet_death_image = load("/users/wherr/documents/julia programs/pet_death.png") |
||
function TamagotchiApp() |
function TamagotchiApp() |
||
Line 705: | Line 705: | ||
current_image = pet_default_image |
current_image = pet_default_image |
||
showall(win) |
showall(win) |
||
info_dialog(introduce(pet)) |
|||
info_dialog(wellbeing(pet)) |
|||
@guarded draw(canvas) do widget |
@guarded draw(canvas) do widget |
||
Line 714: | Line 716: | ||
function update_status() |
function update_status() |
||
str = " Age " * rpad(pet.age ÷ 365, 5) * "Weight " * rpad(pet.weight, 5) * "Hunger " * |
str = " Age " * rpad(pet.age ÷ 365, 5) * "Weight " * rpad(pet.weight, 5) * "Hunger " * |
||
rpad(pet.hunger, 5) * "Happiness " * rpad(pet.happiness, 3) |
rpad(pet.hunger, 5) * "Happiness " * rpad(pet.happiness, 3) |
||
GAccessor.text(status, str) |
GAccessor.text(status, str) |
||
Line 904: | Line 906: | ||
elseif pet.health < 4 && rand() < 0.3 |
elseif pet.health < 4 && rand() < 0.3 |
||
vet() |
vet() |
||
elseif rand() < poop_chance |
elseif rand() < poop_chance && pet.hunger < 6 |
||
poop() |
poop() |
||
elseif rand() < 0. |
elseif rand() < 0.2 * (pet.hunger - 2) |
||
hungry() |
hungry() |
||
else |
else |
||
Line 912: | Line 914: | ||
end |
end |
||
if (pet.weight < 3 || pet.happiness < 3) && pet.health > 4 |
if (pet.weight < 3 || pet.happiness < 3) && pet.health > 4 |
||
warn_dialog(request(pet)) |
|||
pet.health -= 1 |
pet.health -= 1 |
||
end |
end |
||
Line 935: | Line 938: | ||
TamagotchiApp() |
TamagotchiApp() |
||
</lang> |
</lang> |
||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
Revision as of 06:06, 9 March 2021
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). <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>
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>