Сделайте упрощенный Тамагочи / Гига Пэт!

9

Тамагочи и Гига Питомцы были маленькими электронными устройствами, которые имитировали маленького виртуального питомца. У этого питомца было несколько характеристик, таких как здоровье, голод и т. Д.
Я недавно написал этот пример:

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.
    • Если Sleep равен 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

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

ender_scythe
источник
Вы не говорите, что стартовая статистика
Blue
1
Выводы должны быть в «удобном для чтения виде», неоднозначны, и поэтому «раз в секунду». Вы должны отправлять
задания
1
Как это неясно? Хотелось бы, чтобы неясно было больше подробностей, потому что сама неясно.
ender_scythe
2
Песочница больше не помогает, так как ответы уже есть. Люди, которые отметили это как неясное, должны сказать, почему это неясно, вместо того, чтобы быть неясным самим.
ender_scythe
1
@BlueEyedBeast (и другие близкие избиратели) Мне также любопытно, что неясно. У оригинальной версии были некоторые существенные проблемы, но кажется, что исправления исправили это. По крайней мере, для Карджигениката и меня было достаточно ясно представить материалы. Поделитесь некоторыми подробностями о том, что вы находите неясным, чтобы 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 и обработчиков сигналов, приятно иметь случайную проблему, которая (надеюсь) не будет автоматически выиграна одним из выделенных языков игры в гольф.

Вы не указали, как именно указана игра, так что этот погибает с традиционным смертельным криком Тамагочи «Исключение с плавающей запятой (ядро сброшено)».

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

(Dang, моя первая запись в гольф-коде, которую я должен был отредактировать в счетчике байтов. Отредактирован для удаления вызова sleep (), поскольку он на самом деле не соответствовал правилам, как предполагалось.)

Требуется ОС unix-ish для неблокирующего STDIN. Как ни странно, использование параметра switch / case против каскадирования, если / else приводит к более короткому исходному коду, но последующая сжатая версия была длиннее.

<?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";
}
Алекс Хованский
источник
Это не «немедленно реагирует на следующие нажатия клавиш пользователем». Он ожидает, пока не sleep(1)вернется вызов до обработки ввода. Несмотря на то, что он обрабатывает любые команды в очереди перед следующим обновлением, так что это может быть хорошо.
Рэй
Да, отметил. Формулировка была очень расплывчатой, поэтому я немного поверил толкованию, потому что этот путь был короче. :) Если у меня будет время сегодня, я напишу альтернативное решение с помощью временного цикла и представлю оба на рассмотрение.
Алекс Хованский
2

Mathematica, 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, вы должны увидеть что-то вроде этого:

Симуляция тамагочи

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

ngenisis
источник
Хорошо сделано! Я собирался использовать такую ​​структуру, как 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");}}

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");
    }
}
Yodle
источник
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"))

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

О Боже мой. Определенно, здесь есть место для улучшения. Такую проблему легче всего решить с помощью побочных эффектов, а Clojure работает, поэтому я пытаюсь злоупотреблять atomею, чтобы уменьшить объем необходимого кода. К сожалению, я не согласился с планом, так что сейчас это что-то бессмысленное. Я уже получил несколько идей, чтобы уменьшить, хотя.

Это полная программа. Это можно запустить, запустив -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
источник
Это хороший объем кода.
ender_scythe
@ender_scythe Я. Я пытался придерживаться полуприличных методов кодирования в некоторых местах, таких как создание applying-rulesи handle-keypressчистое. Я пишу версию "винт это" прямо сейчас.
Carcigenicate