Faça um Tamagotchi / Giga Pet simplificado!


9

Tamagotchi e Giga Pets eram pequenos dispositivos eletrônicos que simulavam um pequeno animal de estimação virtual. Este animal de estimação tinha várias estatísticas, como saúde, fome etc.
Escrevi recentemente este exemplo:

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

Este é um animal de estimação virtual básico em 467 bytes! Então me perguntei o quão bem os profissionais de código de golfe poderiam fazer, agora o desafio.

O desafio

Faça um programa que rastreie 6 estatísticas de um animal de estimação virtual e atualize-as com o tempo e em resposta à entrada do usuário. As estatísticas são: saúde e dinheiro (começando em 100), comida (começando em 10) e fome, sono e poções (começando em 0).

O programa deve atualizar os valores em resposta aos seguintes eventos:

  • Enquanto o programa não estiver recebendo nenhuma entrada, ele deve executar atualizações em intervalos regulares (o intervalo entre as atualizações não deve ser menor que meio segundo nem maior que um segundo). Cada atualização faz o seguinte:

    • A fome e o sono aumentam em 1.
    • Se a Fome for 80 ou superior, a Vida diminui em 1.
    • Se o Sleep for 80 ou superior, ele será redefinido para 0 e o Fome aumentará 9.
    • Se a Saúde tiver 80 anos ou mais, o dinheiro aumentará 1.
    • Se Saúde for 0, o programa será encerrado.
  • O programa também deve responder imediatamente após as seguintes teclas pressionadas pelo usuário (isso significa que você precisará usar um recurso ou biblioteca de idioma que possa detectar uma tecla pressionada e responder a ela imediatamente, em vez de apenas ler da entrada padrão), executando as seguintes ações:

    • f: Se a fome for maior que 8 e a comida for diferente de zero, a comida diminuirá em 1 e a fome diminuirá em 9.
    • s: O sono é redefinido para 0.
    • p: Se Poções for maior que zero, Poções será reduzida em 1 e Saúde aumentada em 9.
    • b: Se o dinheiro for maior que 8, o dinheiro será reduzido em 9 e as poções aumentadas em 1.
    • t: Se o dinheiro for maior que 8, o dinheiro será reduzido em 9 e o alimento aumentado em 1.

Sempre que os valores das estatísticas mudam, eles devem ser exibidos na tela no formulário . Todas as seis estatísticas devem ser exibidas sempre que alguma delas mudar; e as estatísticas em uma exibição devem ser separadas por vírgulas ou por novas linhas.Stat: value

Esse desafio segue as regras normais de : o programa mais curto que atenda às especificações acima vence. (Observe que, como de costume, se o idioma for mais recente que o da concorrência, o envio deverá ser marcado como não competitivo.)


Você não diz que as estatísticas iniciais são
azul

11
As saídas devem estar em "uma maneira fácil de ler" é ambígua e, portanto, "uma vez por segundo". Você deve enviar desafios para a caixa de areia para obter feedback e melhorá-las antes de postar a principal ...
FlipTack

11
Como isso não está claro? Gostaria claro não ter mais detalhes, porque em si não é claro.
ender_scythe

2
O Sandbox não ajuda mais, pois já existem respostas. As pessoas que marcaram isso como incerto devem dizer por que não está claro, em vez de não estarem claras.
ender_scythe

11
@BlueEyedBeast (e outros eleitores próximos) Também estou curioso para saber o que não está claro. A versão original teve alguns problemas significativos, mas parece que as edições corrigiram isso. No mínimo, era claro o suficiente para eu e o Carcigenicate fornecermos as observações. Compartilhe alguns detalhes sobre o que você acha incerto, para que o ender_scythe possa aprimorá-lo.
Raio

Respostas:


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

Agradeço a necessidade de entrada bruta e atualizações assíncronas na especificação do problema. Mesmo que isso tenha exigido alguma sobrecarga da configuração das ncurses e dos manipuladores de sinais, é bom ter um desafio ocasional que (espero) não será vencido automaticamente por um dos idiomas dedicados ao golfe.

Você não especificou exatamente como o fim do jogo é indicado; portanto, este perece com o grito de morte tradicional de Tamagotchi de "Exceção de ponto flutuante (núcleo despejado)".

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 bytes

(Dang, minha primeira entrada de código de golfe que precisei editar na contagem de bytes. Editada para remover a chamada sleep (), pois não estava em conformidade com as regras conforme o planejado.)

Requer um sistema operacional unix-ish para o STDIN sem bloqueio. Estranhamente, usar switch / case versus cascading se / else produziu um código-fonte mais curto, mas a versão compactada subsequente foi mais longa.

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

Isso "não responde imediatamente após as seguintes teclas pressionadas pelo usuário". Ele espera até que a chamada sleep(1)retorne antes de processar a entrada. Embora ele processe qualquer comando na fila antes de fazer a próxima atualização, pode ser bom.
Ray

Sim, observou. A redação era muito vaga, então tomei liberdade na interpretação, pois era mais curto. :) Se eu tiver tempo hoje, codificarei a solução alternativa com um loop cronometrado e apresentarei ambos para consideração.
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}]

As quebras de linha são importantes porque são caracteres de nova linha na string para que eu possa usar em Rowvez de Column. Se você avaliar isso em um bloco de notas do Mathematica, deverá ver algo assim:

Simulação de Tamagotchi

Você precisa clicar no campo de entrada e digitar seu caractere rapidamente (menos de um segundo) antes Dynamicde atualizar o campo de entrada. Essa dor de cabeça poderia ser totalmente evitada se ela EventHandlerestivesse em sua própria célula, em vez de ser um elemento Row, mas isso exigiria salvar o programa como um arquivo .nb, o que aumentaria bastante a contagem de bytes.


Bom trabalho! Eu ia usar uma estrutura como 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++]]};... isso deve evitar a necessidade de clicar em um campo de entrada. A adição da opção , PassEventsDown -> Trueao final desse código permitirá que você continue editando o bloco de notas, mas pode ser removido no final para economizar bytes :) #
2813 Greg Martin Greg

Obrigado, essa é exatamente a funcionalidade que eu estava procurando inicialmente! Infelizmente, parece que é mais do que o que eu tenho atualmente.
Ngenisis

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

1

Clojure, 1224 702 bytes

V2

Todos os átomos perderam variáveis ​​em vez de estarem dentro de um objeto de estado. Isso por si só se livrou de muito código. Também criei as funções de atalho a!e s!para adicionar e subtrair do atomsmais fácil (basicamente agindo como +=e -=, já que o Clojure não possui esses operadores).

Percebi que provavelmente poderia acabar com atoms se conseguir integrar as entradas principais em a loop. Eu vou ter que ver.

(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. Definitivamente espaço para melhorias aqui. Esse tipo de problema é mais fácil de fazer com efeitos colaterais, e o Clojure é funcional, então estou tentando abusar de atoms para diminuir a quantidade de código necessária. Infelizmente, eu não entrei em um plano, então é meio aleatório agora. Eu já tive algumas idéias para diminuir, no entanto.

É um programa completo. Pode ser executado executando -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))))))

Essa é uma boa quantidade de código lá.
ender_scythe

@ender_scythe Ya. Eu estava tentando aderir a práticas de codificação meio decentes em alguns lugares, como making applying-rulese handle-keypresspuro. Estou escrevendo uma versão "estragar" agora.
Carcigenicate
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.