Зробіть спрощену Tamagotchi / Giga Pet!


9

Tamagotchi та Giga Pets були маленькими електронними пристроями, що імітували маленького віртуального вихованця. У цього домашнього улюбленця було кілька статистичних даних, таких як здоров'я, голод тощо.
Я нещодавно писав цей приклад:

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

Це віртуальний вихованець з голими кістками в 467 байт! Потім я поцікавився, наскільки добре можна зробити кодові профі для гольфу , тож тепер, завдання.

Змагання

Створіть програму, яка відстежує 6 статистичних даних віртуального улюбленця та оновлює їх у часі та у відповідь на введення користувача. Статистика є: здоров'я та гроші (починаючи з 100), їжа (починаючи з 10), голод, сон і зілля (починаючи з 0).

Програма повинна оновити значення у відповідь на наступні події:

  • Поки програма не отримує жодного вводу, вона повинна виконувати оновлення через регулярні інтервали (інтервал між оновленнями не повинен бути коротшим за півсекунди і не довше однієї секунди). Кожне оновлення виконує такі дії:

    • Голод і сон кожен збільшуються на 1.
    • Якщо голод становить 80 і вище, здоров'я знижується на 1.
    • Якщо сон становить 80 або вище, він скидається на 0, а голод збільшується на додаткові 9.
    • Якщо здоров'я становить 80 і більше, гроші збільшуються на 1.
    • Якщо значення Health 0, програма завершується.
  • Програма також повинна негайно реагувати на наступні натискання клавіш користувачем (це означає, що вам потрібно буде використовувати мовну функцію або бібліотеку, яка може виявити натискання клавіші і негайно відповісти на неї, а не просто читати зі стандартного введення), виконуючи наступні дії:

    • f: Якщо голод перевищує 8, а їжа - ненульова, то їжа знижується на 1, а голод - на 9.
    • s: Сон скидається до 0.
    • p: Якщо зілля більше нуля, зілля зменшується на 1, а здоров'я - на 9.
    • b: Якщо грошей більше 8, то гроші зменшуються на 9, а зілля збільшується на 1.
    • t: Якщо грошей більше 8, то гроші зменшуються на 9, а їжа збільшується на 1.

Щоразу, коли значення статистики змінюються, вони повинні відображатися на екрані у формі . Усі шість статистичних даних повинні бути відображені, коли будь-яка з них змінюється; а статистика в межах відображення повинна бути розділена або комами, або новими рядками.Stat: value

Цей виклик відповідає нормальному правила: виграє найкоротша програма, що відповідає вищевказаній специфікації. (Зауважте, що як правило, якщо мова є більш новою, ніж конкуренція, подання має бути позначене як неконкурентне.)


Ви не кажете, що таке стартова статистика
Blue

1
Виходи повинні бути "легкими для читання" - неоднозначні, і тому це "раз у секунду іш". Ви повинні подати виклики в пісочниці, щоб отримати зворотний зв'язок та покращити їх, перш ніж відправляти повідомлення на головну ...
FlipTack

1
Як це незрозуміло? Я б хотів, щоб незрозуміло було більше деталей, тому що саме по собі це незрозуміло.
ender_scythe

2
Пісочниця вже не допомагає, оскільки відповіді вже є. Люди, які позначили це як незрозуміле, повинні сказати, чому це незрозуміло, а не бути незрозумілими самі.
ender_scythe

1
@BlueEyedBeast (та інші близькі виборці) Мені також цікаво, що незрозуміло. У початковій версії були деякі суттєві проблеми, але, схоже, виправлення це виправлено. Принаймні, для Carcigenicate і я було достатньо зрозуміло, щоб вони представили свої матеріали. Поділіться деякими подробицями про те, що вам незрозуміло, тому ender_scythe може покращити це.
Рей

Відповіді:


6

C, 424 406 386 357 байт

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

Я вдячний за необхідність необмеженого введення та асинхронного оновлення в специфікації проблеми. Незважаючи на те, що це вимагало певних накладних витрат з налаштування ncurses та обробників сигналів, приємно мати випадкові виклики, які (сподіваємось) не будуть автоматично виграні однією з виділених мов для гольфу.

Ви не вказали, як саме відображається гра, тому ця гине з традиційним криком смерті Tamagotchi "Виняток з плаваючою точкою (ядро скинуто)".

Безумовно

/* 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 байт

(Данг, мій перший запис у гольф-коді, який мені довелося відредагувати в кількості байтів. Відредаговано для видалення дзвінка сну (), оскільки він насправді не відповідав правилам за призначенням.)

Потрібна ОС Unix-ish для блокування STDIN. Як не дивно, використовуючи перемикач / випадок проти каскадного, якщо / else створював коротший вихідний код, але наступна стисла версія була довшою.

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

Безголівки:

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

Це не "реагує негайно на наступні натискання клавіш користувачем". Він чекає, поки дзвінок sleep(1)повернеться перед обробкою вводу. Хоча він обробляє будь-які команди в черзі перед наступним оновленням, тому це може бути добре.
Рей

Так, зауважив. Формулювання там було великим розпливчастим, тому я взяв трохи свободи в тлумаченні, оскільки цей шлях був коротшим. :) Якщо у мене є час сьогодні, я зашифрую альтернативне рішення тимчасовим циклом і подати їх на розгляд.
Олексій Хованський

2

Математика, 374 байт

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

Розриви рядків важливі, оскільки це символи нового рядка в рядку, щоб я міг використовувати Rowзамість Column. Якщо ви оцінюєте це в зошиті Mathematica, ви повинні побачити щось подібне:

Моделювання Tamagotchi

Ви повинні натиснути на поле введення та швидко (менше секунди) набрати свого персонажа, перш ніж Dynamicвикликати оновлення поля введення. Цього головного болю можна було б уникнути цілком, якби він EventHandlerзнаходився у власній комірці, а не був елементом Row, але це вимагало б збереження програми як .nb-файлу, що значно збільшить кількість байтів.


Хороша робота! Я збирався використовувати структуру на кшталт 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++]]};... це повинно уникнути необхідності клацання в полі введення. Додавання опції , PassEventsDown -> Trueдо кінця цього коду дозволить вам продовжувати редагувати зошит, але його можна буде видалити в самому кінці для економії байтів :)
Грег Мартін

Дякую, саме такий функціонал я шукав спочатку! На жаль, здається, це довше, ніж у мене зараз.
ngenisis

2

C # 6, 567 563 байт

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

Безголівки:

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 байт

V2

Зробив усі атоми втратими змінними, а не знаходитись всередині об'єкта стану. Це одне позбулося багато коду. Я також створив ярлики a!і s!додавати і віднімати з atomsлегше ( в основному діє як +=і -=, так як Clojure не має цих операторів).

Я зрозумів, що, ймовірно, я можу покінчити з atoms, якщо мені вдасться інтегрувати введення ключа в a loop. Я повинен побачити.

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

Безголівки:

(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. Тут безумовно, є можливість вдосконалення. Таку проблему найпростіше зробити з побічними ефектами, а Clojure є функціональною, тому я намагаюся зловживати atoms, щоб зменшити кількість необхідного коду. На жаль, я не входив із планом, тому зараз це начебто випадково. Я вже отримав декілька ідей, щоб зменшити, хоча.

Це повна програма. Її можна запустити бігом -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))))))

Безголівки:

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

Це приємна кількість коду.
ender_scythe

@ender_scythe Я. Я намагався дотримуватися напівпристойних методів кодування в деяких місцях, таких як створення applying-rulesта handle-keypressчистота. Я зараз пишу "накручувану" версію.
Carcigenicate
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.