魔术:聚会高尔夫


30

魔术:聚会是一种交易纸牌游戏,除其他事项外,玩家玩代表生物的卡,然后可以攻击另一位玩家,或通过阻挡来防御另一位玩家的攻击。

在此代码高尔夫挑战赛中,您的程序将代替魔术玩家来决定如何在战斗中封锁。


每个生物都有两个相关属性:力量和韧性。生物的力量是战斗中所能造成的伤害,其韧性是摧毁它所必需的伤害。功效始终至少为0,韧性始终至少为1。

在Magic战斗中,轮到该玩家的玩家宣布其一些生物要攻击对手。然后,另一个被称为防御方的玩家可以将其生物指定为阻挡者。一个生物每次战斗只能阻挡一个生物,但是多个生物可以全部阻挡同一个生物。

宣布阻止者后,攻击者将为每个被阻止的攻击生物决定该生物对阻止它的生物所造成的伤害(等于其力量)的分配方式。

然后,造成损害。每个生物造成的伤害等于其力量。如前所述,被阻挡的攻击生物造成伤害。畅通无阻的攻击生物对防御牌手造成伤害。阻挡生物对其阻挡的生物造成伤害。属于防御者的未被阻挡的生物不会造成伤害。(不需要阻止生物。)

最后,任何受到等于或大于其韧性的伤害的生物都会被摧毁,并从战场上移出。小于生物韧性的任何伤害均无效。


这是此过程的示例:

具有力量P和韧性T的生物表示为 P/T

Attacking:
2/2, 3/3
Defending player's creatures:
1/4, 1/1, 0/1
Defending player declares blockers:
1/4 and 1/1 block 2/2, 0/1 does not block.
Attacking player distributes damage:
2/2 deals 1 damage to 1/4 and 1 damage to 1/1
Damage is dealt:
2/2 takes 2 damage, destroyed.
3/3 takes 0 damage.
1/1 takes 1 damage, destroyed.
1/4 takes 1 damage.
0/1 takes 0 damage.
Defending player is dealt 3 damage.

防守球员在战斗中有3个目标:消灭对手的生物,保留自己的生物,并尽可能减少伤害。此外,力量和韧性更高的生物更有价值。

为了将它们综合为一个度量,我们将说防御玩家从战斗中获得的分数等于其生存生物的力量和防御力的总和减去其对手生存生物的力量和防御力的总和减去一个对防守队员造成的损失的一半。防守球员想最大化这个分数,而进攻球员想最小化它。

在上面显示的战斗中,得分为:

Defending player's surviving creatures:
1/4, 0/1
1 + 4 + 0 + 1 = 6
Attacking player's surviving creature:
3/3
3 + 3 = 6
Damage dealt to defending player:
3
6 - 6 - 3/2 = -1.5

如果防守球员在上述战斗中根本没有阻挡,则得分将为

8 - 10 - (5/2) = -4.5

卫冕玩家的最佳选择本来阻断2/21/11/4,并能阻断3/30/1。如果他们这样做,那么只有1/4那个3/3能够幸免,并且不会对防守球员造成伤害,从而使得分提高

5 - 6 - (0/2) = -1

您的挑战是编写一个程序,该程序将为防守球员输出最佳的盖帽选择。“最佳”是指最大化得分的选择,前提是对手按照您如何阻止的方式以使得分最小的方式分配伤害。

这是一个极大值:损害分布上的最高分,使每种阻断组合的分值最小。


输入:输入将由两个2元组列表组成,其中每个2元组具有以下形式(幂,韧性)。第一个列表将包含每个攻击生物(您对手的生物)的力量和防御力。第二个列表将包含您每个生物的力量和韧性。

元组和列表可以以任何方便的格式表示,例如:

[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]

输出:输出将由一系列2元组组成,格式为(阻塞生物,阻塞生物)-也就是说,您的一个生物之后是其中一个生物。生物将通过其在输入列表中的索引来引用。索引可以是0或1索引。同样,任何方便的格式。任何命令都可以。例如,给定上述输入,来自上方的最佳阻塞方案可能表示为:

[0, 0]    # 1/4 blocks 2/2
[1, 0]    # 1/1 blocks 2/2
[2, 1]    # 0/1 blocks 3/3

例子:

Input:
[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]
Output:
[0, 0]
[1, 0]
[2, 1]

Input:
[[3, 3], [3, 3]]
[[2, 3], [2, 2], [2, 2]]
Output:
[1, 0]
[2, 0]
or
[1, 1]
[2, 1]

Input:
[[3, 1], [7, 2]]
[[0, 4], [1, 1]]
Output:
[1, 0]
or
[0, 0]
[1, 0]

Input:
[[2, 2]]
[[1, 1]]
Output:

(No output tuples).

输入和输出可以通过STDIN,STDOUT,CLA,功能输入/返回等进行。适用标准漏洞。这是代码高尔夫球:以字节为单位的最短代码获胜。


为了阐明规范并提供初步想法,此pastebin提供了Python中的参考解决方案。该best_block函数是解决此难题的示例解决方案,运行该程序将提供更多详细的输入和输出。


18
你应该做这个山丘之王。
PyRulez

1
@Arnauld不,那也是一个有效的答案。
isaacg

Answers:


6

的JavaScript(ES7), 354个  348字节

将输入作为([attackers], [defenders])

(a,d,O,M)=>eval(`for(N=(A=a.push([,0]))**d.length;N--;)O=a[X='map'](([P,T],i)=>S-=((g=(n,l)=>n?l[X](([t,S],i)=>g(n-1,b=[...l],b[i]=[t-1,S])):m=l[X](([t,S])=>s+=t>0&&S,s=0)&&s>m?m:s)(P,l[n=0,i][X](m=([p,t])=>[t,p+t,n+=p])),n<T&&P+T)+(l[i]<1?T/2:-m),S=0,d[X]((x,i)=>l[(j=N/A**i%A|0)<A-1&&o.push([i,j]),j].push(x),o=[],l=a[X](_=>[])))&&S<M?O:(M=S,o)`)

在线尝试!

少打高尔夫球和格式化

该代码与高尔夫版本相同,只是没有map别名和eval()用于可读性的包装。

(a, d, O, M) => {
  for(N = (A = a.push([, 0])) ** d.length; N--;)
    O =
      a.map(([P, T], i) =>
        S -=
          (
            (g = (n, l) =>
              n ?
                l.map(([t, S], i) => g(n - 1, b = [...l], b[i] = [t - 1, S]))
              :
                m = l.map(([t, S]) => s += t > 0 && S, s = 0) && s > m ? m : s
            )(
              P,
              l[n = 0, i].map(m = ([p, t]) => [t, p + t, n += p])
            ),
            n < T && P + T
          ) + (
            l[i] < 1 ? T / 2 : -m
          ),
        S = 0,
        d.map((x, i) =>
          l[
            (j = N / A ** i % A | 0) < A - 1 && o.push([i, j]),
            j
          ].push(x),
          o = [],
          l = a.map(_ => [])
        )
      ) && S < M ? O : (M = S, o)
  return O
}

怎么样?

初始化和主循环

0pushA

A = a.push([, 0])

我们将阻止此虚拟生物,而不是完全阻止任何生物。这样可以简化代码。

ADDN

for(N = (A = a.push([, 0])) ** d.length; N--;)

SMoO

MO

O = (...) && S < M ? O : (M = S, o)

建立防御

l

d.map((x, i) =>              // for each defender x at position i:
  l[                         //   update l[]:
    (j = N / A ** i % A | 0) //     j = index of the attacker that we're going to block
    < A - 1 &&               //     if this is not the 'dummy' creature:
    o.push([i, j]),          //       add the pair [i, j] to the current solution
    j                        //     use j as the actual index to update l[]
  ].push(x),                 //   push x in the list of blockers for this attacker
  o = [],                    //   initialize o to an empty list
  l = a.map(_ => [])         //   initialize l to an array containing as many empty lists
                             //   that there are attackers
)                            // end of map()

优化攻击

攻击者的决定彼此无关。攻击方的全局最优值是每个攻击者的局部最优值之和。

PTi

a.map(([P, T], i) => ...)

l[i]

l[n = 0, i].map(m = ([p, t]) => [t, p + t, n += p])

n

gP

(g = (n, l) =>            // n = remaining damage points; l = list of blockers
  n ?                     // if we still have damage points:
    l.map(([t, S], i) =>  //   for each blocker of toughness t and score S at index i:
      g(                  //     do a recursive call:
        n - 1,            //       decrement the number of damage points
        b = [...l],       //       create a new instance b of l
        b[i] = [t - 1, S] //       decrement the toughness of blocker i
      )                   //     end of recursive call
    )                     //   end of map()
  :                       // else:
    m =                   //   update the best score m (the lower, the better):
      l.map(([t, S]) =>   //     for each blocker of toughness t and score S:
        s += t > 0 && S,  //       add S to s if this blocker has survived
        s = 0             //       start with s = 0
      ) &&                //     end of map()
      s > m ? m : s       //     set m = min(m, s)
)                         //

更新后卫得分

在对攻击者进行每次迭代之后,我们使用以下内容更新防御者得分:

S -= (n < T && P + T) + (l[i] < 1 ? T / 2 : -m)

如果幸存下来,左边部分减去攻击者的分数。如果根本没有阻止攻击,则右侧部分减去攻击者的韧性一半,否则,将获得最佳攻击者得分(从防御角度看,这是最差的得分)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.