Faites un Tamagotchi / Giga Pet simplifié!

9

Tamagotchi et Giga Pets étaient de petits appareils électroniques qui simulaient un petit animal virtuel. Cet animal avait plusieurs statistiques, comme la santé, la faim, etc.
J'ai récemment écrit cet exemple:

import msvcrt,os,sys;d=m=100;h=s=t=p=0;f=10
while 1:
 os.system('cls'if os.name=='nt'else'clear');print("health:",d,"\nhunger:",h,"\nsleep:",s,"\nfood:",f,"\npotions:",p,"\nmoney:",m);t+=1
 if msvcrt.kbhit():
  k=ord(msvcrt.getch())
  if k==102 and h>8 and f:f-=1;h-=9
  if k==115:s=0
  if k==112 and p:p-=1;d+=9
  if k==98 and m>8:m-=9;p+=1
  if k==116 and m>8:m-=9;f+=1
 if t>99:
  t=0;h+=1;s+=1
  if s>80:s=0;h+=9
  if h>80:d-=1
  if d<1:sys.exit(0)
  if d>79:m+=1

Ceci est un animal de compagnie virtuel à nu en 467 octets! Je me suis ensuite demandé dans quelle mesure les pros du golf pouvaient faire du code , alors maintenant, le défi.

Le défi

Créez un programme qui suit 6 statistiques d'un animal virtuel et les met à jour au fil du temps et en réponse à l'entrée de l'utilisateur. Les statistiques sont les suivantes: santé et argent (à partir de 100), nourriture (à partir de 10) et faim, sommeil et potions (à partir de 0).

Le programme doit mettre à jour les valeurs en réponse aux événements suivants:

  • Pendant que le programme ne reçoit aucune entrée, il doit effectuer des mises à jour à intervalles réguliers (l'intervalle entre les mises à jour ne doit pas être inférieur à une demi-seconde ni supérieur à une seconde). Chaque mise à jour effectue les opérations suivantes:

    • La faim et le sommeil augmentent chacun de 1.
    • Si la faim est de 80 ou plus, la santé diminue de 1.
    • Si le sommeil est de 80 ou plus, il est réinitialisé à 0 et la faim augmente de 9 supplémentaires.
    • Si la santé est de 80 ou plus, l'argent augmente de 1.
    • Si Health est 0, le programme se ferme.
  • Le programme doit également répondre immédiatement aux pressions de touches suivantes de l'utilisateur (cela signifie que vous devrez utiliser une fonction de langue ou une bibliothèque qui peut détecter une touche enfoncée et y répondre immédiatement, plutôt que de simplement lire à partir d'une entrée standard), les actions suivantes:

    • f: Si la faim est supérieure à 8 et que la nourriture n'est pas nulle, la nourriture est diminuée de 1 et la faim est diminuée de 9.
    • s: Le sommeil est réinitialisé à 0.
    • p: Si Potions est supérieur à zéro, Potions est diminué de 1 et Santé est augmentée de 9.
    • b: Si l'argent est supérieur à 8, l'argent est diminué de 9 et les potions sont augmentées de 1.
    • t: Si l'argent est supérieur à 8, l'argent est diminué de 9 et la nourriture est augmentée de 1.

Chaque fois que les valeurs des statistiques changent, elles doivent être affichées à l'écran dans le formulaire . Les six statistiques doivent être affichées chaque fois que l'une d'entre elles change; et les statistiques dans un affichage doivent être séparées soit par des virgules soit par des sauts de ligne.Stat: value

Ce défi suit les règles normales du : le programme le plus court conforme aux spécifications ci-dessus l'emporte. (Notez que, comme d'habitude, si la langue est plus récente que la compétition, la soumission doit être marquée comme non concurrente.)

ender_scythe
la source
Vous ne dites pas quelles sont les statistiques de départ
Blue
1
Les sorties doivent être "d'une manière facile à lire" est ambiguë, et donc "une fois par seconde ish". Vous devriez soumettre des défis au bac à sable pour obtenir des commentaires et les améliorer avant de publier sur le principal ...
FlipTack
1
Comment cela n'est-il pas clair? Je souhaite peu clair avait plus de détails, car lui-même n'est pas clair.
ender_scythe
2
Sandbox n'aide plus, car il y a déjà des réponses. Les personnes qui ont marqué cela comme peu clair devraient dire pourquoi ce n'est pas clair, au lieu de l'être eux-mêmes.
ender_scythe
1
@BlueEyedBeast (et d'autres électeurs proches) Je suis également curieux de savoir ce qui n'est pas clair. La version originale avait quelques problèmes importants, mais il semble que les modifications aient corrigé cela. À tout le moins, il était suffisamment clair pour Carcigenicate et moi de soumettre des observations. Partagez quelques détails sur ce que vous trouvez peu clair afin que ender_scythe puisse l'améliorer.
Ray

Réponses:

6

C, 424 406 386 357 octets

#define x(a,b,c)if(*#a==C){if(b>8){c-=9;}Z=0;}
L,M=100,H,S=-1,F=10,P,Z,C;t(){H++;S++;L-=H>79;if(S>79)S=0,H+=9;Z=1/L/2;alarm(1);}main(){nodelay(initscr(),L=M);signal(14,t);for(t(H=S);C=getch();Z=Z||printf("\rhealth: %d,hunger: %d,sleep: %d,food: %d,potions: %d,money: %d\n",L,H,S,F,P,M)){x(s,9,S=9;S)x(p,P+8,P--;L+=18;L)x(f,H,F--;H)x(b,M,P++;M)x(t,M,F++;M)}}

J'apprécie la nécessité d'une entrée brute et de mises à jour asynchrones dans les spécifications du problème. Même si cela nécessitait des frais généraux de la configuration de ncurses et des gestionnaires de signaux, il est agréable d'avoir le défi occasionnel qui (espérons-le) ne sera pas automatiquement remporté par l'une des langues de golf dédiées.

Vous n'avez pas spécifié exactement comment le jeu est indiqué, donc celui-ci périt avec le cri de mort traditionnel Tamagotchi de "l'exception à virgule flottante (noyau vidé)".

Non golfé

/* Playing a bit fast and loose with the prototyping rules by omitting these;
 * none of the functions I'm using from them *exactly* match the default
 * prototype of `int f();`
 */
//#include <curses.h>
//#include <stdio.h>
//#include <signal.h>
//#include <unistd.h>

#define x(a,b,c)if(*#a==C){if(b>8){c-=9;}Z=0;}
L,M=100,H,S=-1,F=10,P,Z,C;

t() {
    H++;
    S++;
    L-=H>79;
    if(S>79)S=0,H+=9;
    Z=1/L/2;//0 if L>0. otherwise the pet dies of a floating point error
    alarm(1);
}

main(){
    nodelay(initscr(),L=M);
    signal(14,t);
    for(t(H=S); C=getch(); Z=Z||printf("\rhealth: %d,hunger: %d,sleep: %d,food: %d,potions: %d,money: %d\n",L,H,S,F,P,M)){
        x(s,9,S=9;S)
        x(p,P+8,P--;L+=18;L)
        x(f,H,F--;H)
        x(b,M,P++;M)
        x(t,M,F++;M)
    }
}
Rayon
la source
2

PHP, 396 413 octets

(Dang, ma première entrée de golf de code que j'ai dû modifier en nombre d'octets. Modifié pour supprimer l'appel sleep (), car il ne respectait pas vraiment les règles comme prévu.)

Nécessite un système d'exploitation unix pour le STDIN non bloquant. Curieusement, l'utilisation de switch / case par rapport à la cascade si / else produisait un code source plus court, mais la version compressée suivante était plus longue.

<?eval(gzinflate(base64_decode('bY5BT8MwDIXv/Ao0WWujtVJ7YmtITwiNAwhp3KutOE20pImWVGxa999J1IEAcbH87O892wlUqsEjtmnivD/d5rLd9qZPCHX+gFvdOPTNTpl2L/su3bw9PL1kBaEwMHAMLCsocFaGKhjo0BT0Q0iFaUnO4JmXGlPyPZI8TWHPeIe+nbIIGccJqsGTXbi4p4EKEEt4Qs6xH+rlfA6c5DnwEYacregFlcMvziUk/FLQnzN79drosiOIxV/X7kroeklAh9BxsQD7m/H/MXxi4iKoob5bxRuCTtpFHd8Jn8ab0S7iLOz0pO5LgkfpQ0wrzGyNW+VFBSJ7Nj2eKtDZozHvFfBsPfQdHioYso1CtBW47NV4aXpXgb2Z0csn')));

Non golfé:

<?
shell_exec('stty -icanon');
stream_set_blocking(STDIN, 0);
$u = $s = $p =0;
$f = 10;
$h = $m = 100;
while(1) {
    $t=time();
    while(1)
        if (($k = fgetc(STDIN)) || time() > $t)
            break;
    if ($k == 'f'){
        if ($u > 8 && $f) --$f | $u -= 9;
    } elseif ($k == 's')
        $s = 0;
    elseif ($k == 'p') {
        if ($p) --$p | $h += 9;
    } elseif ($k == 'b') {
        if ($m > 8) $m -= 9 | ++$p;
    } elseif ($k == 't') {
        if ($m > 8) $m -= 9 | ++$f;
    } else {
        if (++$u > 79) --$h;
        if (++$s > 79) $s = 0 | $u += 9;
        if ($h > 79) ++$m;
        if ($h < 1) exit;
    }
    echo"Health:$h,Money:$m,Food:$f,Hunger:$u,Sleep:$s,Potions:$p\n";
}
Alex Howansky
la source
Cela ne "répond pas immédiatement aux touches suivantes de l'utilisateur". Il attend le sleep(1)retour de l'appel avant de traiter l'entrée. Bien qu'il traite toutes les commandes en file d'attente avant de faire la prochaine mise à jour, cela peut donc être correct.
Ray
Ouais, noté. Le libellé était un peu vague, alors j'ai pris une certaine liberté d'interprétation parce que ce chemin était plus court. :) Si j'ai le temps aujourd'hui, je coderai la solution alternative avec une boucle chronométrée et les présenterai pour examen.
Alex Howansky
2

Mathematica, 374 octets

h=m=100;f=10;g=s=p=0;RunScheduledTask[g++;s++;If[g>79,h--];If[s>79,s=0;g+=9];If[h>79,m++];If[h<1,Quit[]]];Dynamic@Row[{EventHandler[InputField[],"KeyDown":>Switch[CurrentValue@"EventKey","f",If[g>8&&f>0,f--;g-=9],"s",s=0,"p",If[p>0,p--;h+=9],"b",If[m>8,m-=9;p++],"t",If[m>8,m-=9;f++]]],"
Health: ",h,"
Money: ",m,"
Food: ",f,"
Hunger: ",g,"
Sleep: ",s,"
Potions: ",p}]

Les sauts de ligne sont importants car ce sont des caractères de nouvelle ligne dans la chaîne que je pourrais utiliser à la Rowplace de Column. Si vous évaluez cela dans un cahier Mathematica, vous devriez voir quelque chose comme ceci:

Simulation Tamagotchi

Vous devez cliquer dans le champ de saisie et saisir rapidement (moins d'une seconde) votre caractère avant Dynamicde mettre à jour le champ de saisie. Ce casse-tête pourrait être évité entièrement si le EventHandlerétait dans sa propre cellule plutôt que d'en être un élément Row, mais cela nécessiterait d'enregistrer le programme sous forme de fichier .nb, ce qui augmenterait considérablement le nombre d'octets.

ngenisis
la source
Bon travail! J'allais utiliser une structure comme CurrentValue[EvaluationNotebook[], NotebookEventActions] = {"KeyDown" :> Switch[CurrentValue@"EventKey", "f", If[g > 8 && f > 0, f--; g -= 9], "s", s = 0, "p", If[p > 0, p--; h += 9], "b", If[m > 8, m -= 9; p++], "t", If[m > 8, m -= 9; f++]]};... cela devrait vous permettre d'éviter de cliquer dans un champ de saisie. L'ajout de l'option , PassEventsDown -> Trueà la fin de ce code vous permettra de continuer à modifier le bloc-notes, mais peut être supprimé à la fin pour économiser des octets :)
Greg Martin
Merci, c'est exactement la fonctionnalité que je recherchais au départ! Malheureusement, il semble que ce soit plus long que ce que j'ai actuellement.
ngenisis
2

C # 6, 567 563 octets

using System;using System.Threading;class T{int L,M,F=10,H,S,P;static void Main(){T t=new T();}T(){M=L=100;var W=new Thread(new ThreadStart(Q));W.Start();while(1>0){var r=Console.Read();bool B=0>1,K=1>0;if(r=='f'&H>8&F>0){F--;H-=9;B=K;}if(r=='s'){S=0;B=K;}if(r=='p'&P>0){P--;L+=9;B=K;}if(r=='b'&M>8){M-=9;P++;B=K;}if(r=='t'&M>8){M-=9;F++;B=K;}if(B)p();}}void Q(){while(1>0){H++;S++;if(H>79)L--;if(S>79){S=0;H+=9;}if(L>79)M++;L*=L/L;p();Thread.Sleep(500);}}void p(){Console.Write($"\nhealth: {L}\nhunger: {H}\nsleep: {S}\nfood: {F}\nmoney: {M}\npotions: {P}\n");}}

Non golfé:

using System;
using System.Threading;
class T
{
    int L,M,F=10,H,S,P;
    static void Main()
    {
        T t=new T();
    }
    T()
    {
        M=L=100;
        var W=new Thread(new ThreadStart(Q));
        W.Start();
        while(1>0)
        {
            var r=Console.Read();
            var B=0>1;
            if(r=='f'&H>8&F>0){F--;H-=9;B=1>0;}
            if(r=='s'){S=0;B=1>0;}
            if(r=='p'&P>0){P--;L+=9;B=1>0;}
            if(r=='b'&M>8){M-=9;P++;B=1>0;}
            if(r=='t'&M>8){M-=9;F++;B=1>0;}
            if(B)p();
        }
    }
    void Q()
    {
        while(1>0)
        {
            H++;S++;
            if(H>79)L--;
            if(S>79){S=0;H+=9;}
            if(L>79)M++;
            L*=L/L;
            p();
            Thread.Sleep(500);
        }
    }
    void p()
    {
        Console.Write($"\nhealth: {L}\nhunger: {H}\nsleep: {S}\nfood: {F}\nmoney: {M}\npotions: {P}\n");
    }
}
Yodle
la source
1

Clojure, 1224 702 octets

V2

Fait que tous les atomes perdent des variables au lieu d'être à l'intérieur d'un objet d'état. Cela seul a éliminé beaucoup de code. J'ai également créé les fonctions de raccourci a!et s!pour ajouter et soustraire du atomsplus facile (agissant essentiellement comme +=et -=, puisque Clojure n'a pas ces opérateurs).

Je me suis rendu compte que je pourrais probablement me débarrasser de atoms si j'arrivais à intégrer une entrée clé dans a loop. Je vais devoir voir.

(ns bits.golf.pet.v2.petms)(def h(atom 100))(def j(atom 0))(def s(atom 0))(def f(atom 10))(def p(atom 0))(def m(atom 100))(defn a[sa n](swap! sa #(+ % n)))(defn v[sa n](swap! sa #(- % n)))(defn c[](a j 1)(a s 1)(if(>=@j 80)(v h 1))(if (>=@s 80)(do(reset! s 0)(a j 9)))(if(>= @h 80)(a m 1)))(defn l[k](case k\f(if(> @j 8)(do(v f 1)(v j 9)))\s(reset! s 0) \p(if(>@p 0)(do(v p 1)(a h 9)))\b(if(> @m 8)(do(v m 9)(a p 1)))\t(if(>@m 8)(do(v m 9)(a f 1)))nil))(defn b[](.start(Thread.^Runnable(fn[](while(>@h 0)(l(first (read-line))))))))(defn -main[](b)(while(>@h 0)(Thread/sleep 500)(c)(println(str"Health: "@h"\nHunger: " @j"\nSleep: "@s"\nFood: "@f"\nPotions: "@p"\nMoney:"@m"\n")))(println"You died!\n"))

Non golfé:

(ns bits.golf.pet.v2.pet)

; 100 0 0 10 0 100
(def he (atom 100))
(def hu (atom 0))
(def sl (atom 0))
(def fo (atom 10))
(def po (atom 0))
(def mo (atom 100))

(defn a! [sa n]
  (swap! sa #(+ % n)))

(defn s! [sa n]
  (swap! sa #(- % n)))

(defn apply-rules []
    (a! hu 1)
    (a! sl 1)
    (if (>= @hu 80)
      (s! he 1))
    (if (>= @sl 80)
      (do
        (reset! sl 0)
        (a! hu 9)))
    (if (>= @he 80)
      (a! mo 1)))

(defn handle-keypress [k]
    (case k
      \f (if (> @hu 8)
           (do
             (s! fo 1)
             (s! hu 9)))
      \s (reset! sl 0)
      \p (if (> @po 0)
           (do
             (s! po 1)
             (a! he 9)))
      \b (if (> @mo 8)
           (do
             (s! mo 9)
             (a! po 1)))
      \t (if (> @mo 8)
           (do
             (s! mo  9)
             (a! fo 1)))
      nil))


(defn start-listener []
  (.start
    (Thread. ^Runnable
      (fn []
        (while (> @he 0)
            (handle-keypress (first (read-line))))))))

(defn -main []
  (start-listener)
  (while (> @he 0)
    (Thread/sleep 500)

    (apply-rules)

    (println (str
               "Health: " @he "\n"
               "Hunger: " @hu "\n"
               "Sleep: " @sl "\n"
               "Food: " @fo "\n"
               "Potions: " @po "\n"
               "Money:" @mo "\n")))

  (println "You died!\n"))

V1

Oh mon Dieu. Certainement matière à amélioration ici. Ce type de problème est plus facile à faire avec les effets secondaires, et Clojure est fonctionnel, donc j'essaie d'abuser de atoms pour réduire la quantité de code nécessaire. Malheureusement, je ne suis pas entré avec un plan, donc c'est un peu hasardeux en ce moment. J'ai déjà eu quelques idées pour rétrécir.

C'est un programme complet. Il peut être exécuté en exécutant -main.

(ns bits.golf.pet)(defrecord S[he hu sl fo po mo])(def new-state(->S 100 0 0 10 0 100))(def state(atom new-state))(defn update![sa k f](swap! sa #(update % k f)))(defn apply-rules[s](let [s' (atom s)u! #(update! s' %1 %2)g #(get @s' %)](u! :hu inc)(u! :sl inc)(if(>=(g :hu)80)(u! :he dec))(if(>= (g :sl)80)(do(u! :sl (fn[_]0))(u! :hu #(+ % 9))))(if(>=(g :he)80)(u! :mo inc))@s'))(defn get-input [](let [raw (read-line)](first raw)))(defn handle-keypress[s k](let [s'(atom s)u! #(update! s' %1 %2)g #(get @s' %)](case k\f(if (> (g :hu)8)(do(u! :fo dec)(u! :hu #(- % 9))))\s(u! :sl (fn [_] 0))\p(if(> (g :po)0)(do(u! :po dec)(u! :he #(+ % 9))))\b(if(>(g :mo))(do(u! :mo #(- % 9))(u! :po inc)))\t(if(>(g :mo)8)(do(u! :mo #(- % 9))(u! :fo inc)))nil@s')))(defn start-listener[](.start(Thread.^Runnable(fn[](while true(let[k(get-input)](swap! state #(handle-keypress % k))))))))(defn -main[](start-listener)(let[g #(get @%1 %2)](while true(Thread/sleep 500)(swap! state #(apply-rules %))(println(str"Health: "(g state :he)"\nHunger: "(g state :hu)"\n""Sleep: " (g state :sl)"\nFood: "(g state :fo)"\nPotions: "(g state :po)"\n""Money:"(g state :mo)"\n"))(if(<=(g state :he)0)(do(println"You died!\n")(reset! state new-state))))))

Non golfé:

(ns bits.golf.pet)

(defrecord State [he hu sl fo po mo])

(def new-state (->State 100 0 0 10 0 100))

(def state (atom new-state))

(defn update! [sa k f]
  (swap! sa #(update % k f)))

(defn apply-rules [s]
  (let [s' (atom s)
        u! #(update! s' %1 %2)
        g #(get @s' %)]
    (u! :hu inc)
    (u! :sl inc)
    (if (>= (g :hu) 80)
      (u! :he dec))
    (if (>= (g :sl) 80)
      (do
        (u! :sl (fn [_] 0))
        (u! :hu #(+ % 9))))
    (if (>= (g :he) 80)
      (u! :mo inc))
    @s'))

(defn get-input []
  (let [raw (read-line)]
    (first raw)))

(defn handle-keypress [s k]
  (let [s' (atom s)
        u! #(update! s' %1 %2)
        g #(get @s' %)]
    (case k
      \f (if (> (g :hu) 8)
           (do
             (u! :fo dec)
             (u! :hu #(- % 9))))
      \s (u! :sl (fn [_] 0))
      \p (if (> (g :po) 0)
           (do
             (u! :po dec)
             (u! :he #(+ % 9))))
      \b (if (> (g :mo))
           (do
             (u! :mo #(- % 9))
             (u! :po inc)))
      \t (if (> (g :mo) 8)
           (do
             (u! :mo #(- % 9))
             (u! :fo inc)))
      nil
      @s')))

(defn start-listener []
  (.start
    (Thread. ^Runnable
      (fn []
        (while true
          (let [k (get-input)]
            (swap! state #(handle-keypress % k))))))))

(defn -main []
  (start-listener)
  (let [g #(get @%1 %2)]
    (while true
      (Thread/sleep 500)

      (swap! state #(apply-rules %))

      (println (str
                 "Health: " (g state :he) "\n"
                 "Hunger: " (g state :hu) "\n"
                 "Sleep: " (g state :sl) "\n"
                 "Food: " (g state :fo) "\n"
                 "Potions: " (g state :po) "\n"
                 "Money:" (g state :mo) "\n"))

      (if (<= (g state :he) 0)
        (do
          (println "You died!\n\n\n\n\n")
          (reset! state new-state))))))
Carcigenicate
la source
C'est une bonne quantité de code là-bas.
ender_scythe
@ender_scythe Ya. J'essayais d'adhérer à des pratiques de codage à moitié décentes dans certains endroits, comme faire applying-ruleset handle-keypresspur. J'écris une version "à visser" en ce moment.
Carcigenicate