Machen Sie ein vereinfachtes Tamagotchi / Giga-Haustier!

9

Tamagotchi und Giga Pets waren kleine elektronische Geräte, die ein kleines virtuelles Haustier simulierten. Dieses Haustier hatte mehrere Statistiken, wie Gesundheit, Hunger usw.
Ich habe kürzlich dieses Beispiel geschrieben:

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

Dies ist ein virtuelles Haustier mit nackten Knochen in 467 Bytes! Ich habe mich dann gefragt, wie gut die Code-Golf-Profis das machen können, also jetzt die Herausforderung.

Die Herausforderung

Erstellen Sie ein Programm, das 6 Statistiken eines virtuellen Haustieres verfolgt und diese im Laufe der Zeit und als Reaktion auf Benutzereingaben aktualisiert. Die Statistiken sind: Gesundheit und Geld (ab 100), Essen (ab 10) und Hunger, Schlaf und Tränke (ab 0).

Das Programm sollte die Werte als Reaktion auf die folgenden Ereignisse aktualisieren:

  • Während das Programm keine Eingabe empfängt, sollte es in regelmäßigen Abständen Aktualisierungen durchführen (das Intervall zwischen den Aktualisierungen sollte nicht kürzer als eine halbe Sekunde und nicht länger als eine Sekunde sein). Jedes Update führt Folgendes aus:

    • Hunger und Schlaf erhöhen sich jeweils um 1.
    • Wenn der Hunger 80 oder mehr beträgt, verringert sich die Gesundheit um 1.
    • Wenn der Schlaf 80 oder höher ist, wird er auf 0 zurückgesetzt und der Hunger um weitere 9 erhöht.
    • Wenn die Gesundheit 80 oder höher ist, erhöht sich das Geld um 1.
    • Wenn Health 0 ist, wird das Programm beendet.
  • Das Programm muss auch sofort auf die folgenden Tastendrücke des Benutzers reagieren (dies bedeutet, dass Sie eine Sprachfunktion oder -bibliothek verwenden müssen, die eine gedrückte Taste erkennen und sofort darauf reagieren kann, anstatt nur von der Standardeingabe zu lesen) die folgenden Aktionen:

    • f: Wenn der Hunger größer als 8 ist und das Essen ungleich Null ist, wird das Essen um 1 und der Hunger um 9 verringert.
    • s: Der Schlaf wird auf 0 zurückgesetzt.
    • p: Wenn Tränke größer als Null sind, werden Tränke um 1 verringert und die Gesundheit um 9 erhöht.
    • b: Wenn das Geld größer als 8 ist, wird das Geld um 9 verringert und die Tränke um 1 erhöht.
    • t: Wenn das Geld größer als 8 ist, wird das Geld um 9 verringert und das Essen um 1 erhöht.

Wenn sich die Werte der Statistiken ändern, müssen sie im Formular auf dem Bildschirm angezeigt werden Stat: value . Alle sechs Statistiken müssen angezeigt werden, wenn sich eine von ihnen ändert. und die Statistiken innerhalb einer Anzeige müssen entweder durch Kommas oder durch Zeilenumbrüche getrennt werden.

Diese Herausforderung folgt den normalen Regeln: Das kürzeste Programm, das der obigen Spezifikation entspricht, gewinnt. (Beachten Sie, dass wie üblich, wenn die Sprache neuer als der Wettbewerb ist, die Einreichung als nicht konkurrierend markiert werden muss.)

ender_scythe
quelle
Sie sagen nicht, was die Startstatistiken sind
Blue
1
Die Ausgaben müssen "leicht lesbar" sein und sind mehrdeutig. Sie sind also "einmal pro Sekunde". Sie sollten Herausforderungen an die Sandbox senden, um Feedback zu erhalten und diese zu verbessern, bevor Sie an main ...
FlipTack
1
Wie ist das unklar? Ich wünschte, unklar hätte mehr Details, weil selbst unklar ist.
ender_scythe
2
Sandbox hilft nicht mehr, da es bereits Antworten gibt. Die Leute, die dies als unklar markiert haben, sollten sagen, warum es unklar ist, anstatt selbst unklar zu sein.
ender_scythe
1
@BlueEyedBeast (und andere enge Wähler) Ich bin auch neugierig, was unklar ist. Die ursprüngliche Version hatte einige bedeutende Probleme, aber es scheint, dass die Änderungen das behoben haben. Zumindest war es für Carcigenicate und mich klar genug, Beiträge einzureichen. Teilen Sie einige Details darüber mit, was Sie unklar finden, damit ender_scythe es verbessern kann.
Ray

Antworten:

6

C, 424 406 386 357 Bytes

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

Ich schätze die Notwendigkeit von Roheingaben und asynchronen Aktualisierungen in der Problemspezifikation. Auch wenn dies einen gewissen Aufwand für das Setup und die Signalhandler von ncurses erfordert, ist es schön, gelegentlich die Herausforderung zu haben, die (hoffentlich) nicht automatisch von einer der dedizierten Golfsprachen gewonnen wird.

Sie haben nicht genau angegeben, wie das Spielende angezeigt wird, daher geht dieses mit dem traditionellen Tamagotchi-Todesschrei "Gleitkomma-Ausnahme (Core Dumped)" zugrunde.

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)
    }
}
Strahl
quelle
2

PHP, 396 413 Bytes

(Dang, mein erster Code-Golf-Eintrag, den ich in Byte-Anzahl bearbeiten musste. Bearbeitet, um den Aufruf sleep () zu entfernen, da er nicht wirklich den beabsichtigten Regeln entsprach.)

Benötigt ein Unix-Betriebssystem für das nicht blockierende STDIN. Seltsamerweise verwendete switch / case versus cascading if / else einen kürzeren Quellcode, aber die nachfolgende komprimierte Version war länger.

<?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";
}
Alex Howansky
quelle
Dies reagiert nicht "sofort auf die folgenden Tastendrücke des Benutzers". Es wartet, bis der Aufruf sleep(1)zurückkehrt, bevor Eingaben verarbeitet werden. Obwohl vor dem nächsten Update alle Befehle in der Warteschlange verarbeitet werden, ist dies möglicherweise in Ordnung.
Ray
Ja, bemerkt. Der Wortlaut dort war sehr vage, so dass ich mir bei der Interpretation etwas Freiheit nahm, weil dieser Weg kürzer war. :) Wenn ich heute Zeit habe, werde ich die alternative Lösung mit einer Zeitschleife codieren und beide zur Prüfung präsentieren.
Alex Howansky
2

Mathematica, 374 Bytes

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

Die Zeilenumbrüche sind wichtig, da es sich um Zeilenumbrüche in der Zeichenfolge handelt, die ich Rowanstelle von verwenden könnte Column. Wenn Sie dies in einem Mathematica-Notizbuch auswerten, sollten Sie Folgendes sehen:

Tamagotchi-Simulation

Sie müssen in das Eingabefeld klicken und Ihren Charakter schnell (weniger als eine Sekunde) eingeben, bevor Dynamicdas Eingabefeld aktualisiert wird. Diese Kopfschmerzen könnten vollständig vermieden werden, wenn sich das Programm EventHandlerin einer eigenen Zelle befindet und nicht ein Element von. Dies Rowwürde jedoch das Speichern des Programms als .nb-Datei erfordern, was die Anzahl der Bytes erheblich erhöhen würde.

Genisis
quelle
Gute Arbeit! Ich wollte eine Struktur wie 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++]]};... verwenden, damit Sie nicht in ein Eingabefeld klicken müssen. Wenn Sie die Option , PassEventsDown -> Trueam Ende dieses Codes hinzufügen, können Sie das Notizbuch weiter bearbeiten, es kann jedoch ganz am Ende entfernt werden, um Byte zu sparen :)
Greg Martin
Danke, das ist genau die Funktionalität, nach der ich ursprünglich gesucht habe! Leider scheint es länger zu dauern als das, was ich derzeit habe.
Genisis
2

C # 6, 567 563 Bytes

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

Clojure, 1224 702 Bytes

V2

Alle Atome haben Variablen verloren, anstatt sich in einem Zustandsobjekt zu befinden. Das allein hat viel Code losgeworden. Ich habe auch die Verknüpfungsfunktionen erstellt a!und s!um die atomseinfacheren zu addieren und zu subtrahieren (im Grunde genommen als +=und -=, da Clojure diese Operatoren nicht hat).

Mir wurde klar, dass ich atoms wahrscheinlich abschaffen könnte, wenn ich es schaffe, Schlüsseleingaben in a zu integrieren loop. Ich muss sehen.

(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

Oh mein Gott. Hier gibt es definitiv Raum für Verbesserungen. Diese Art von Problem ist am einfachsten mit Nebenwirkungen zu lösen, und Clojure ist funktionsfähig, also versuche ich zu missbrauchenatom s zu , um die benötigte Codemenge zu verringern. Leider habe ich keinen Plan erstellt, daher ist das momentan ein Zufall. Ich habe schon ein paar Ideen bekommen, um mich zu verkleinern.

Es ist ein volles Programm. Es kann durch Ausführen ausgeführt werden -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))))))
Carcigenicate
quelle
Das ist eine schöne Menge Code.
ender_scythe
@ender_scythe Ya. Ich habe versucht, mich an einigen Stellen an halbwegs anständige Codierungspraktiken zu halten, wie z . B. Making applying-rulesund handle-keypressPure. Ich schreibe gerade eine "Screw-It" -Version.
Carcigenicate