Имитация битвы между двумя существами

16

Добро пожаловать, храбрый игрок в гольф код! Сегодня вы окажетесь посреди великой битвы между гоблином и эльфом!

    goblin attacks elf!
    elf dodges!
    elf attacks goblin!
    elf hits goblin for 13 damage!
    goblin has 37 health left.
    goblin attacks elf!
    goblin hits elf for 1 damage!
    elf has 49 health left.
    elf attacks goblin!
    elf hits goblin for 19 damage!
    goblin has 18 health left.
    goblin attacks elf!
    goblin hits elf for 26 damage!
    elf has 23 health left.
    elf attacks goblin!
    elf hits goblin for 20 damage!
    goblin has been slain!

Соревнование

Ваша задача - симулировать битву, как описано выше. Вы получите ввод в этой форме:

creatureName health strength defense accuracy agility

Например, битва между гоблином и эльфом будет:

goblin 50 40 35 3 2 elf 50 35 30 4 5

Первое и второе существа будут чередовать атаки.

  • Распечатать 'creatureName атакует otherCreatureName!'
  • Проверьте, не уклоняется ли существо. Существо будет уклоняться от атаки, если (его умножение на ловкость rand (), деленное на 2) больше, чем (умение атакующего умножить на rand ()).
    • Если существо уклоняется, выведите «creatureName dodges!»
    • В противном случае рассчитайте нанесенный урон путем вычитания (умножение силы противника на ранд ()) и (умножение времени защиты на ранда (), деленное на 2). Минимальный урон равен 1. Напечатайте 'creatureName поражает otherCreatureName за (x) урон!' Затем выведите «creatureName имеет (x) оставленное здоровье». если здоровье существа не меньше 0, в этом случае ...
      • Если здоровье существа равно 0 или меньше, выведите «creatureName было убито!» и закончить программу.

правила

  • Самый короткий код выигрывает.
  • Не печатайте буквально «creatureName», а заменяйте его именем существа. Не печатайте «(x) урон» или «(x) здоровье;» заменить их на фактическую сумму. (Я должен указать это, потому что некоторые люди очень креативны с нарушением правил.: P)
Дверная ручка
источник
2
Зачем усложнять спецификацию, вдвое снижая ловкость и защиту?
Питер Тейлор
@Peter Потому что иначе битвы заняли бы слишком много времени.
Дверная ручка
2
Моя точка зрения была такой: почему бы не изменить ввод, например, на goblin 50 40 18 3 2 elf 50 35 15 4 5?
Питер Тейлор,
@ Питер Мех, это просто показалось слишком странным - почему защита была намного ниже? Во всяком случае, это головоломка; нет причин не делать этого: P
дверная ручка
Я думаю, что неясно, осталось ли у «creatureName (x) здоровья». должен быть напечатан в последнем раунде (когда существо убито), и в случае, если это должно (я предполагал, что это не должно), если (x) должно быть всегда 0, или это может быть отрицательное число.
эпидемиолог

Ответы:

4

APL ( 249 244 242)

На этот раз процедурный стиль, поэтому (по крайней мере, в Dyalog) вы должны вставить это в окно редактора. Я назвал его G(первая строка - это имя, я включил его, потому что именно так оно и отображается в окне редактора, поэтому его, вероятно, следует учитывать).

грамм
⎕ML ← 3
DA ← {(⊂ ↑ ⍵), ⍎¨1 ↓ ⍵} ¨ ↓ 2 6⍴A⊂⍨ '' ≠ A ← ⍞
→ 5
⎕ ← (↑ D) 'уловок!
AD ← DA
⎕ ← (↑ А) 'атаки', '!', ⍨ ↑ D
→ 4 / ⍨> /? А [6], D [5]
⎕ ← A [1], 'хиты', D [1], 'за', 'ущерб!', ⍨D [2] - ← 1⌈ - / A [3], ⌈D [4] ÷ 2
→ 12 / ⍨D [2] ≤0
D ← D [1], «имеет», D [2], «здоровье осталось!»
→ 5
D ← D [1], «был убит!»

(edit: использовались числовые GOTO вместо меток строк. Оказывается, что (по крайней мере, в Dyalog) все, что определяет метка X:, - Xэто номер строки, поэтому с таким же успехом можно использовать числа напрямую.)

Мэринус
источник
6

Perl, 254 + 1

for((@a[0..5],@b)=split;$a[1]>0;@c=@a,@a=@b,@b=@c){say"$a[0] attacks $b[0]!\n",rand$b[5]/2<rand$a[4]?do{($==rand($a[2])-rand$b[3]/2)<1and$==1;"$a[0] hits $b[0] for $= damage!\n$b[0] has ",($b[1]-=$=)>0?"$b[1] health left.":"been slain!"}:"$b[0] dodges!"}

Беги с perl -nM5.010(или perl -nE '<code>'). За мета , то -nотсчеты переключателя как один дополнительный символ. В этом коде нет никаких хитростей в игре в гольф, кроме, возможно, использования в $=качестве переменной урона для сохранения int.

Изменить: Надеюсь, расчет ущерба теперь правильный.

Илмари Каронен
источник
6

CoffeeScript 454 432

Передайте строку, bчтобы получить результаты. Я подумал, что было бы веселее иметь графический анимационный вывод, поэтому я собрал демо. Просто измените поле ввода, чтобы изменить статистику и имена. Фотографии из jpg.to, который является неофициальным API Google-изображений.

Супер Экшн Демо

battle simulator in action

b=(s)->
 r=Math.random
 p=s.split ' '
 n=p.map Number
 l=''
 o=(x...)->l+=x.join(' ')+'!\n'
 while 1|i=!i
  c=(x)->n[i*6+x]*r()
  d=(x)->n[(i||6)+x]*r()
  t=->d(4)/2>c 5
  h=->Math.max c(2)-d(3)/2,1
  a=p[i*6]
  b=p[6+i*-6]
  o a,'attacks',b
  if c(5)/2>d 4
   e=Math.ceil h()
   q=n[(i||6)+1]-=e
   o a,'hits',b,'for',e,'damage'
   o b,'has',q,'health left'if q>0
  else
   o b,'dodges'
  if q<1
   o b,'has been slain'
   break
 l

Рекомендуемые входы (предложите свой):

charmander 50 40 25 3 2 bulbasaur 90 30 40 4 5
voldemort 9999 10 5 1 1 batman 20 50 10 1010 30
разбойник
источник
Wow, that's great! :D I would accept this answer if I could accept two, but I said in the rules that the shortest would be accepted, and I can only accept one answer :( So +1. And voldemort 9999 haha :D
Doorknob
@Doorknob, as an extra bonus, you can give it numbers like 10e42, but your browser may freeze...
Brigand
6

Ruby, 292 264

v=$*
def p*a;puts a*' 'end
loop{a,b=v[0],v[6]
w=v.map &:to_i
p a,:attacks,b+?!
w[11]*rand/2>w[4]*rand ? (p b,:dodges!):(h=v[7]=w[7]-=d=[rand(w[2])-rand(w[9])/2,1].max
p a,:hits,b,:for,d,:damage!
p b,:has,h<1?"been slain!":"#{h} health left."
h<1&&exit)
v.rotate!6}

My first code golf entry; how that method definition parses is beyond me :)

Is it OK to read the input from command-line parameters (e.g. ruby battle.rb goblin 50 40 35 3 2 elf 50 35 30 4 5)?

Ideone run

epidemian
источник
Yes, that is okay.
Doorknob
5

JavaScript; 347 341 333

As I always do, I shall start off with my own solution:

for(m=prompt().split(' '),r=Math.random,a=console.log,c=0,d=6;;){if(a(m[c]+' attacks '+m[d]+'!'),r()*m[c+4]>r()*m[d+5]/2){if(a(m[c]+' hits '+m[d]+' for '+(h=Math.max(~~(r()*m[c+2]-r()*m[d+3]/2),1))+' damage!'),(m[d+1]-=h)<1){a(m[d]+' has been slain!');break}a(m[d]+' has '+m[d+1]+' health left.')}else a(m[d]+' dodges!');t=c;c=d;d=t}

EDIT: apparently assigning console.log to a variable breaks on some browsers, so here's the same code with a function declaration instead:

for(m=prompt().split(' '),r=Math.random,a=function(x){console.log(x)},c=0,d=6;;){if(a(m[c]+' attacks '+m[d]+'!'),r()*m[c+4]>r()*m[d+5]/2){if(a(m[c]+' hits '+m[d]+' for '+(h=Math.max(~~(r()*m[c+2]-r()*m[d+3]/2),1))+' damage!'),(m[d+1]-=h)<1){a(m[d]+' has been slain!');break}a(m[d]+' has '+m[d+1]+' health left.')}else a(m[d]+' dodges!');t=c;c=d;d=t}

I was thinking of changing it to alert, but that would just be evil :P

Doorknob
источник
i get a Uncaught TypeError: Illegal invocation because of a=console.log. would'nt you have to bind the console object as context, e.g a=console.log.bind(console)?
C5H8NNaO4
@C5H Hmm, that's odd. It works for me.
Doorknob
Just checked it in Firefox,Safari and Chrome, in Firefox it works =) Chrome gives me above, and Safari a TypeError
C5H8NNaO4
@C5H :( Maybe I could replace it with alert, but that would be very annoying :P
Doorknob
:P Yes that would be indeed annoying, but at least it would save "6" characters and avoids the TypeError =) But i guess its Ok, at least it runs on Firefox =)
C5H8NNaO4
4

Python: 393

I squeezed a little harder, if I had 3 I could probably do print = p to shorten it by a few more, but I don't think there is much left in this one.

393:

from random import randrange as r
x = input().split()
t=range
a,b=6,0
for i in t(1,6)+t(7,12):x[i]=int(x[i])
while x[b+1] > 0:
 a,b=b,a;print x[a]+" attacks "+x[b]
 if r(x[a+5]/2)>r(x[b+5]):print x[a]+' dodges!';continue
 d=max(r(x[a+2])-r(x[b+3]/2),1);print x[a]," hits ",x[b]," for ",d," damage!";x[b+1]-=d
 if x[b+1]>0:print x[b]," has ",x[b+1]," health left."
print x[b]," has been slain"

399:

from random import randrange as r
x = raw_input().split()
t=range
a,b=6,0
for i in t(1,6)+t(7,12):x[i]=int(x[i])
while x[b+1] > 0:
 a,b=b,a;print x[a]+" attacks "+x[b]
 if r(x[a+5]/2) > r(x[b+5]):print x[a]+' dodges!';continue
 d=max(r(x[a+2])-r(x[b+3]/2),1);print x[a]," hits ",x[b]," for ",d," damage!";x[b+1]-=d                        if x[b+1]>0:print x[b]," has ",x[b+1]," health left."
print x[b]," has been slain"

I think people are skipping that if you have a good condition in the loop, you don't need to check if the target is below health.


источник
I check the health twice, in the loop header to end the battle, and in the loop to print either "has been slayed" or "hits ...", because the double health check is shorter than an extra console.log
C5H8NNaO4
4

JavaScript: 340 306

339:

for(m=Math.random,a=prompt().split(" "),c=[a,a.splice(6)],e;0<+c[0][1]&&0<+c[1][1];)c.reverse(),console.log(c[0][0]+" attacks "+c[1][0]+"!\n"+(c[0][4]*m()<c[1][5]*m()/2?c[1][0]+" dodges!":c[0][0]+" hits "+c[1][0]+" for "+(e=1+(c[0][2]*m()-c[1][3]*m()/2|0))+" damage!\n"+c[1][0]+" has "+(0>(c[1][1]-=e)?"been slain!":c[1][1]+" health left.")))

306:

for(var m=Math.random,a=prompt().split(" "),b=a.splice(6),d,e;0<+a[1]&&0<+b[1];d=a,a=b,b=d)console.log(a[0]+" attacks "+b[0]+"!\n"+(a[4]*m()<b[5]*m()/2?b[0]+" dodges!":a[0]+" hits "+b[0]+" for "+(e=a[2]*m()-b[3]*m()/2|0,e<=0?e=1:e)+" damage!\n"+b[0]+" has "+(0>(b[1]-=e)?"been slain!":b[1]+" health left.")))

Sample output:

goblin attacks elf!
elf dodges!
elf attacks goblin!
elf hits goblin for 21 damage!
goblin has 29 health left.
goblin attacks elf!
elf dodges!
elf attacks goblin!
elf hits goblin for 15 damage!
goblin has 14 health left.
goblin attacks elf!
goblin hits elf for 1 damage!
elf has 49 health left.
elf attacks goblin!
elf hits goblin for 16 damage!
goblin has been slain!   

Edit notes: +1 character, i missed the "!" after "dodges"
Oh and i forgot to actually put an output after "Sample output"
Changed the header to JavaScript, as @tbodt suggests

C5H8NNaO4
источник
Why don't you call it JavaScript to avoid confusing people?
tbodt
@tbodt I didn't thought it would confuse people =) Changed it to Javascript instead
C5H8NNaO4
3

R: 387 characters

a=scan(,"");i=as.integer;r=runif;C=cat;X=data.frame(i(a[2:6]),i(a[8:12]));z=1;Y=c(a[1],a[7]);repeat{p=1+z%%2;n=X[,p];m=X[,-p];N=Y[p];M=Y[-p];C(N,"attacks",M,"\n");if(r(1)*n[5]<r(1)*m[5]/2){C(M,"dodges!\n")}else{C(N,"hits",M,"for",d<-max(round(n[2]*r(1)-m[3]*r(1)/2),1),"damages!\n");h=max(m[1]-d,0);if(h){C(M,"has",X[1,-p]<-h,"health left\n")}else{C(M,"has been slained!");break}};z=z+1}

Or fully-developed, with indentations and comments, to make things clearer:

a=scan(,"")                        # Read stdin as character vector
i=as.integer
r=runif
C=cat
X=data.frame(i(a[2:6]),i(a[8:12])) # Data frame with opponents stats
z=1                                # Turn counter 
Y=c(a[1],a[7])                     # Vector of opponents name
repeat{                            # shorter than while(T)
    p=1+z%%2                       # R indexing starts with 1 not 0
    n=X[,p]                        # Attacking opponent stats
    m=X[,-p]                       # Defending opponent stats
    N=Y[p]                         # Attacking opponent name
    M=Y[-p]                        # Defending opponent name
    C(N,"attacks",M,"\n")          # By default, cat separates elements with a space
    if(r(1)*n[4]<r(1)*m[5]/2){
        C(M,"dodges!\n")
    }else{
        C(N,"hits",M,"for",d<-max(round(n[2]*r(1)-m[3]*r(1)/2),1),"damages!\n")
        h=max(m[1]-d,0)            # Health after the strike
        if(h){                     # If health is not 0
            C(M,"has",X[1,-p]<-h,"health left\n")
        }else{                     # If it is
            C(M,"has been slained!")
            break
            }
    }
    z=z+1
}
plannapus
источник
2

C# - 464 453 chars

After a couple of nights on this I can't seem to get even close to the other entries (not that surprising for C#). Still room for improvement I suspect. No especially clever tricks.

using System;using System.Linq;class P{static void Main(string[]a){int D,h=1,z=6;
var n=a.Select(x=>int.TryParse(x,out D)?D:0).ToList();var r=new Random();Func<int>
R=()=>r.Next(101);for(;h>0;z=z>0?0:6){D=(n[8-z]*R()-n[3+z]*R()/2)/100;var d=n[5+z]
*R()/2>n[10-z]*R();h=d?h:n[1+z]-=D=D<1?1:D;Console.Write("{0} attacks {1}!\n"+(d?
"{1} dodges!\n":"{0} hits {1} for {2} damage!\n")+(d?"":"{1} has {3}\n"),a[6-z],a
[z],D,h>0?h+" health left.":"been slain!");}}}

Commented:

using System;
using System.Linq;
class P
{
    static void Main(string[] a)
    {
        int D, // string to int parsing and attack damage 
            h = 1, // health 
            z = 6; // index

        // painful requirement to convert the input strings to integers
        var n = a.Select(x => int.TryParse(x, out D) ? D : 0).ToList();

        // set up a function to return a new random number
        var r = new Random();
        Func<int> R = () => r.Next(101);

        // we'll exit the loop when the defender's health (h) is <= 0.
        // z is used as an index offset to get values out of the list, it flips between 0 an 6 each round
        for (; h > 0; z = z > 0 ? 0 : 6)
        {
            // calculate damage
            D = (n[8 - z] * R() - n[3 + z] * R() / 2) / 100;

            // see if defender dodges
            var d = n[5 + z] * R() / 2 > n[10 - z] * R();

            // subtract health from defender if necessary. store health of defender in h
            h = d ? h : n[1 + z] -= D = D < 1 ? 1 : D;

            // print the round
            Console.Write(
                "{0} attacks {1}!\n" + (d ? "{1} dodges!\n" : "{0} hits {1} for {2} damage!\n") + 
                (d ? "" : "{1} has {3}\n"), a[6 - z], a[z], D, h > 0 ? h + " health left." : "been slain!");
        }
    }
}
Igby Largeman
источник
1

Python 3, 314

from random import*
r=random
p=print
I=input().split()
H=1
while H>0:s,a,H,D,G=map(int,I[2:5:2]+I[7::2]);N=I[6];p(I[0],"attacks",N+"!");I=I[6:]+I[:6];X=max(int(s*r()-D*r()/2),1)*(G*r()/2<a*r());I[1]=H=H-X;X<1and p(N,"dodges!")or p(I[6],"hits",N,"for",X,"damage!\n"+N,"has",["been slain!","%s health left."%H][H>0])
Reinstate Monica
источник