Crea un Tamagotchi / Giga Pet semplificato!


9

Tamagotchi e Giga Pets erano piccoli dispositivi elettronici che simulavano un animaletto virtuale. Questo animale domestico aveva diverse statistiche, come salute, fame, ecc
. Di recente ho scritto questo esempio:

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

Questo è un animale domestico a ossa nude in 467 byte! Mi sono quindi chiesto quanto bene i professionisti del codice golf potrebbero fare, quindi ora la sfida.

La sfida

Crea un programma che tiene traccia di 6 statistiche di un animale domestico virtuale e le aggiorna nel tempo e in risposta all'input dell'utente. Le statistiche sono: salute e denaro (a partire da 100), cibo (a partire da 10) e fame, sonno e pozioni (a partire da 0).

Il programma dovrebbe aggiornare i valori in risposta ai seguenti eventi:

  • Mentre il programma non riceve input, dovrebbe eseguire gli aggiornamenti a intervalli regolari (l'intervallo tra gli aggiornamenti non deve essere inferiore a mezzo secondo né più lungo di un secondo). Ogni aggiornamento procede come segue:

    • Fame e sonno aumentano ciascuno di 1.
    • Se la fame è 80 o superiore, la salute diminuisce di 1.
    • Se il sonno è 80 o superiore, viene reimpostato su 0 e la fame aumenta di altri 9.
    • Se la salute è 80 o superiore, il denaro aumenta di 1.
    • Se Health è 0, il programma viene chiuso.
  • Il programma deve inoltre rispondere immediatamente ai seguenti tasti premuti dall'utente (ciò significa che sarà necessario utilizzare una funzione o una libreria linguistica in grado di rilevare un tasto premuto e rispondere immediatamente, anziché limitarsi a leggere dallo standard input), eseguendo le seguenti azioni:

    • f: Se la fame è maggiore di 8 e il cibo è diverso da zero, allora il cibo è diminuito di 1 e la fame è diminuita di 9.
    • s: La sospensione viene reimpostata su 0.
    • p: Se Pozioni è maggiore di zero, Pozioni viene ridotta di 1 e Salute aumenta di 9.
    • b: Se il denaro è maggiore di 8, il denaro viene ridotto di 9 e le pozioni aumentate di 1.
    • t: Se il denaro è maggiore di 8, il denaro viene ridotto di 9 e il cibo viene aumentato di 1.

Ogni volta che i valori delle statistiche cambiano, devono essere visualizzati sullo schermo nel modulo . Tutte e sei le statistiche devono essere visualizzate ogni qualvolta cambiano; e le statistiche all'interno di un display devono essere separate da virgole o da righe.Stat: value

Questa sfida segue le normali regole del : vince il programma più breve conforme alle specifiche sopra. (Tieni presente che, come al solito, se la lingua è più recente della concorrenza, la presentazione deve essere contrassegnata come non competitiva.)


Non dici quali sono le statistiche di partenza
Blue

1
Gli output devono essere in un "modo di facile lettura" è ambiguo, e quindi "una volta al secondo ish". Dovresti inviare sfide alla sandbox per ottenere feedback e migliorarle prima di pubblicare sul main ...
FlipTack

1
Come è poco chiaro? Vorrei che non fosse chiaro avere più dettagli, perché di per sé non è chiaro.
ender_scythe,

2
Sandbox non aiuta più, poiché ci sono già risposte. Le persone che hanno contrassegnato questo come non chiaro dovrebbero dire perché non è chiaro, invece di essere poco chiare.
ender_scythe,

1
@BlueEyedBeast (e altri elettori stretti) Sono anche curioso di sapere cosa non è chiaro. La versione originale aveva alcuni problemi significativi, ma sembra che le modifiche lo abbiano risolto. Per lo meno, era abbastanza chiaro per me e Carcigenicate fornire osservazioni. Condividi alcuni dettagli su ciò che trovi poco chiaro in modo che ender_scythe possa migliorarlo.
Ray,

Risposte:


6

C, 424 406 386 357 byte

#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)}}

Apprezzo la necessità di input non elaborati e aggiornamenti asincroni nelle specifiche del problema. Anche se ciò ha richiesto un certo sovraccarico dall'impostazione di ncurses e dai gestori del segnale, è bello avere la sfida occasionale che (si spera) non sarà automaticamente vinto da uno dei linguaggi del golf dedicati.

Non hai specificato esattamente come viene indicato il game over, quindi questo perisce con il tradizionale grido di morte Tamagotchi di "Eccezione in virgola mobile (core scaricato)".

Ungolfed

/* 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)
    }
}

2

PHP, 396 413 byte

(Dang, la mia prima voce di golf in codice che ho dovuto modificare nel conteggio dei byte. Modificato per rimuovere la chiamata sleep (), poiché non era realmente conforme alle regole come previsto.)

Richiede un sistema operativo unix-ish per STDIN non bloccante. Stranamente, l'utilizzo di switch / case rispetto a cascata se / else produceva un codice sorgente più breve, ma la successiva versione compressa era più lunga.

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

Ungolfed:

<?
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";
}

Questo non "risponde immediatamente ai seguenti tasti premuti dall'utente". Attende che la chiamata sleep(1)ritorni prima di elaborare l'input. Anche se elabora i comandi in coda prima di eseguire il prossimo aggiornamento, quindi potrebbe andare bene.
Ray,

Sì, notato. La formulazione era molto vaga, quindi mi sono liberato dell'interpretazione perché in questo modo era più breve. :) Se oggi ho tempo, codificherò la soluzione alternativa con un ciclo a tempo e presenterò entrambi per considerazione.
Alex Howansky,

2

Mathematica, 374 byte

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}]

Le interruzioni di riga sono importanti perché sono caratteri di nuova riga nella stringa, quindi è possibile utilizzarli al Rowposto di Column. Se lo valuti in un notebook Mathematica dovresti vedere qualcosa del genere:

Simulazione Tamagotchi

Devi fare clic nel campo di input e digitare rapidamente (meno di un secondo) il tuo personaggio prima che Dynamicil campo di input venga aggiornato. Questo mal di testa potrebbe essere evitato del tutto se EventHandlerfosse nella propria cella anziché essere un elemento di Row, ma ciò richiederebbe il salvataggio del programma come file .nb che aumenterebbe notevolmente il conteggio dei byte.


Bel lavoro! Stavo per usare una struttura come 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++]]};... questo dovrebbe farti evitare la necessità di fare clic in un campo di input. L'aggiunta dell'opzione , PassEventsDown -> Truealla fine di quel codice ti consentirà di continuare a modificare il blocco note, ma può essere rimosso alla fine per risparmiare byte :)
Greg Martin,

Grazie, questa è esattamente la funzionalità che stavo cercando inizialmente! Sfortunatamente sembra che sia più lungo di quello che ho attualmente.
ngenisi,

2

C # 6, 567 563 byte

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");}}

Ungolfed:

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");
    }
}

1

Clojure, 1224 702 byte

V2

Ha reso variabili tutti gli atomi anziché essere all'interno di un oggetto stato. Solo questo si è sbarazzato di molto codice. Ho anche creato le funzioni di scelta rapida a!e s!per aggiungere e sottrarre dal atomspiù semplice (sostanzialmente agendo come +=e -=, poiché Clojure non ha quegli operatori).

Mi sono reso conto che probabilmente avrei potuto eliminare atoms se riuscissi a integrare l'input chiave in a loop. Dovrò vedere

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

Ungolfed:

(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

Ohdeargod. Sicuramente margini di miglioramento qui. Questo tipo di problema è più facile da fare con gli effetti collaterali e Clojure è funzionale, quindi sto cercando di abusareatom s per ridurre la quantità di codice necessario. Sfortunatamente, non ho aderito a un piano, quindi è un po 'casuale al momento. Ho già avuto alcune idee per ridurmi, però.

È un programma completo. Può essere eseguito eseguendo -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))))))

Ungolfed:

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

È una buona quantità di codice lì.
ender_scythe,

@ender_scythe Ya. Stavo cercando di aderire a pratiche di codifica decente in alcuni luoghi, come fare applying-rulese handle-keypresspuro. Sto scrivendo una versione "avvitabile" in questo momento.
Carcigenicato il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.