Zrób uproszczony Tamagotchi / Giga Pet!

9

Tamagotchi i Giga Pets były małymi urządzeniami elektronicznymi, które symulowały małego wirtualnego zwierzaka. To zwierzę miało kilka statystyk, takich jak zdrowie, głód itp.
Niedawno napisałem ten przykład:

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

To wirtualne zwierzę bez kości w 467 bajtach! Zastanawiałem się wtedy, jak dobrze potrafią golfiści , więc teraz wyzwanie.

Wyzwanie

Stwórz program, który śledzi 6 statystyk wirtualnego zwierzaka i aktualizuje je wraz z upływem czasu i odpowiedziami użytkowników. Statystyki to: zdrowie i pieniądze (od 100), jedzenie (od 10) oraz głód, sen i mikstury (od 0).

Program powinien zaktualizować wartości w odpowiedzi na następujące zdarzenia:

  • Chociaż program nie otrzymuje żadnych danych wejściowych, powinien przeprowadzać aktualizacje w regularnych odstępach czasu (odstęp między aktualizacjami nie powinien być krótszy niż pół sekundy ani dłuższy niż jedna sekunda). Każda aktualizacja wykonuje następujące czynności:

    • Głód i sen każdego wzrostu o 1.
    • Jeśli Głód wynosi 80 lub więcej, Zdrowie spada o 1.
    • Jeśli tryb uśpienia wynosi 80 lub więcej, jest resetowany do 0, a głód wzrasta o dodatkowe 9.
    • Jeśli Zdrowie wynosi 80 lub więcej, Pieniądze wzrosną o 1.
    • Jeśli stan zdrowia wynosi 0, program kończy się.
  • Program musi również natychmiast reagować na następujące naciśnięcia klawiszy użytkownika (oznacza to, że będziesz musiał użyć funkcji języka lub biblioteki, która może wykryć naciśnięcie klawisza i zareagować na niego natychmiast, a nie tylko czytać ze standardowego wejścia), wykonując następujące działania:

    • f: Jeśli Głód jest większy niż 8, a Jedzenie jest niezerowe, to Jedzenie zmniejsza się o 1, a Głód zmniejsza się o 9.
    • s: Tryb uśpienia jest resetowany do 0.
    • p: Jeśli Mikstury są większe od zera, Mikstury są zmniejszane o 1, a Zdrowie zwiększa się o 9.
    • b: Jeśli Pieniądze są większe niż 8, to Pieniądze są zmniejszane o 9, a Mikstury zwiększane o 1.
    • t: Jeśli Pieniądze są większe niż 8, to Pieniądze są zmniejszane o 9, a Jedzenie jest zwiększane o 1.

Ilekroć zmieniają się wartości statystyk, muszą być one wyświetlane na ekranie w formularzu . Wszystkie sześć statystyk musi być wyświetlane przy każdej zmianie; a statystyki w obrębie wyświetlacza muszą być oddzielone przecinkami lub znakami nowej linii.Stat: value

To wyzwanie jest normalne zasady: wygrywa najkrótszy program zgodny z powyższą specyfikacją. (Pamiętaj, że jak zwykle, jeśli język jest nowszy niż konkurs, zgłoszenie musi być oznaczone jako niekonkurujące).

ender_scythe
źródło
Nie mówisz, jakie są początkowe statystyki
Niebieski,
1
Dane wyjściowe muszą być „łatwe do odczytania” są niejednoznaczne, a więc „raz na sekundę ish”. Powinieneś przesłać wyzwania do piaskownicy, aby uzyskać opinie i poprawić je, zanim opublikujesz post na głównej ...
FlipTack,
1
Jak to jest niejasne? Chciałbym, żeby niejasne było więcej szczegółów, ponieważ samo jest niejasne.
ender_scy
2
Piaskownica już nie pomaga, ponieważ są już odpowiedzi. Ludzie, którzy oznaczyli to jako niejasne, powinni powiedzieć, dlaczego jest niejasny, zamiast siebie.
ender_scy
1
@BlueEyedBeast (i inni bliscy wyborcy) Jestem również ciekawy, co jest niejasne. Oryginalna wersja miała kilka istotnych problemów, ale wygląda na to, że zmiany to naprawiły. Przynajmniej było jasne, że Carcigenicate i ja przedstawiliśmy uwagi. Podziel się szczegółami na temat tego, co uważasz za niejasne, aby ender_scy mogli to poprawić.
Ray

Odpowiedzi:

6

C, 424 406 386 357 bajtów

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

Doceniam potrzebę nieprzetworzonych danych wejściowych i aktualizacji asynchronicznych w specyfikacji problemu. Mimo że wymagało to trochę narzutu od konfiguracji ncurses i obsługi sygnałów, miło jest mieć okazjonalne wyzwanie, które (miejmy nadzieję) nie zostanie automatycznie wygrane przez jeden z dedykowanych języków golfowych.

Nie określiłeś dokładnie, w jaki sposób kończy się gra, więc ten ginie z tradycyjnym okrzykiem śmierci Tamagotchi „Wyjątek zmiennoprzecinkowy (zrzut rdzenia)”.

Nie golfił

/* 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)
    }
}
Promień
źródło
2

PHP, 396 413 bajtów

(Dang, mój pierwszy kod golfowy, który musiałem edytować w liczbie bajtów. Edytowany, aby usunąć wywołanie sleep (), ponieważ tak naprawdę nie było zgodne z regułami zgodnie z przeznaczeniem).

Wymaga systemu operacyjnego uniksowego dla nieblokującego STDIN. Dziwne, że użycie przełącznika / wielkość liter w porównaniu do kaskadowania, jeśli / else produkuje krótszy kod źródłowy, ale późniejsza skompresowana wersja była dłuższa.

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

Nie golfowany:

<?
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
źródło
To nie „natychmiast reaguje na kolejne naciśnięcia klawiszy przez użytkownika”. sleep(1)Przed przetworzeniem danych wejściowych czeka na wywołanie powrotu. Chociaż przed kolejną aktualizacją przetwarza wszelkie kolejkowane polecenia, więc może być w porządku.
Ray
Tak, odnotowano. Sformułowanie było bardzo niejasne, więc skorzystałem z interpretacji, ponieważ ta droga była krótsza. :) Jeśli mam dzisiaj czas, koduję alternatywne rozwiązanie za pomocą pętli czasowej i przedstawię oba do rozważenia.
Alex Howansky
2

Mathematica, 374 bajty

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

Podziały linii są ważne, ponieważ są znakami nowej linii w ciągu, więc mógłbym użyć Rowzamiast Column. Jeśli ocenisz to w notatniku Mathematica, powinieneś zobaczyć coś takiego:

Symulacja Tamagotchi

Musisz kliknąć pole wejściowe i szybko (mniej niż sekundę) wpisać swoją postać, zanim Dynamicspowoduje ona aktualizację pola wejściowego. Tego bólu głowy można było całkowicie uniknąć, gdyby EventHandlerznajdował się w swojej komórce, a nie był elementem Row, ale wymagałoby to zapisania programu jako pliku .nb, co znacznie zwiększyłoby liczbę bajtów.

ngenisis
źródło
Dobra robota! Zamierzałem użyć struktury takiej jak 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++]]};... to powinno pozwolić ci uniknąć konieczności klikania pola wejściowego. Dodanie opcji , PassEventsDown -> Truena końcu tego kodu pozwoli kontynuować edycję notatnika, ale można go usunąć na samym końcu, aby zaoszczędzić bajty :)
Greg Martin
Dzięki, dokładnie takiej funkcjonalności szukałem początkowo! Niestety wydaje się, że jest dłuższy niż obecnie.
ngenisis
2

C # 6, 567 563 bajtów

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

Nie golfowany:

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");
    }
}
Jodła
źródło
1

Clojure, 1224 702 bajtów

V2

Sprawiło, że wszystkie atomy traciły zmienne zamiast znajdować się w obiekcie stanu. Już sam pozbyłem się dużo kodu. Stworzyłem również funkcje skrótów a!oraz s!dodawanie i odejmowanie atomsłatwiejszych (w zasadzie działa jako +=i -=, ponieważ Clojure nie ma tych operatorów).

Zdałem sobie sprawę, że prawdopodobnie mógłbym pozbyć się atoms jeśli uda mi się zintegrować wejście klucza do loop. Będę musiał zobaczyć

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

Nie golfowany:

(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

Drogi Boże. Zdecydowanie miejsce na poprawę tutaj. Tego rodzaju problem najłatwiej jest rozwiązać z efektami ubocznymi, a Clojure działa, więc próbuję nadużyć, atomaby zmniejszyć potrzebną ilość kodu. Niestety nie wdałem się w plan, więc teraz jest to trochę przypadkowe. Mam już kilka pomysłów na zmniejszenie.

To pełny program. Można go uruchomić, uruchamiając -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))))))

Nie golfowany:

(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
źródło
To niezła ilość kodu.
ender_scy
@ender_scythe Ya. Starałem się przestrzegać w niektórych miejscach na wpół przyzwoitych praktyk kodowania, takich jak tworzenie applying-rulesi handle-keypressczyszczenie. Piszę teraz wersję „zakręconą”.
Carcigenicate