找到战争游戏的结果


15

找到战争游戏的结果

当我上小学时,有一场“石头剪刀布”式的游戏,我们在集会期间,等我们的老师,在课间休息时会玩。我们称之为“战争”。然而,经过一些搜索,事实证明这是“ Shotgun Game”(根据WikiHow)的简单得多的变体。由于规则略有不同,因此我将其称为“战争”:

2个人坐在彼此对面。游戏的目的是“杀死”另一位玩家。每回合,您可以玩以下3个动作之一:

  • 重新装填:您有一杆枪可以一次射击。必须先重新加载它,然后才能每次射击。在已经拥有弹药的情况下重新加载是合法的,但不会执行任何操作。用两只手轻敲您的太阳穴即可象征重新装填。每个玩家从0弹药开始。

  • 警卫:唯一安全的举动。如果您在守卫时被枪杀,则不会死。双臂交叉在胸前象征着警卫。

  • :开枪。要成功射击,您必须自上次射击以来已重新加载。如果您的对手正在加注,您将获胜。如果他们也开火,而且你们俩都有弹药,那就平局了。如果他们在守卫,您就浪费了弹药。虽然没有弹药射击是合法的举动,但它却无能为力,使您像重新装弹一样容易受伤。指向其他玩家象征着射击。

玩法与RPS相似,在于每个玩家同时放弃选择(我们在回合之间两次敲击双腿以保持节奏,但这对挑战并不重要)。

挑战:

您的任务是找到战争游戏的结局。它可以是功能或完整程序。

输入值

  • 每个玩家选择的回合选项将由一个字符/字符串表示:

    • r:重新加载

    • g:守卫

    • f:着火

  • 输入将是成对列表,带分隔符/不带分隔符的字符串或沿这些行的其他任何内容。

Python中的示例输入可以为[("r", "g"), ("f", "r")],这意味着在第一回合中第一位玩家重新装弹,第二位玩家守卫。在第二个回合中,第一个玩家射击,而第二个玩家重新加载。玩家一赢得这场比赛。同样的输入可以选择性地为代表"r g f r""rgfr""rg fr" "rg-fr"...

您可以假设以下内容:

  • 输入内容将与您选择的格式匹配,并且仅包含有效字符。

  • 有人会在100转内死亡。

但是,您不能假设某人死亡时转弯结束。

输出量

一个值,指示谁(或谁先赢*)。您可以选择每种方案的输出内容,但必须考虑以下因素:

  • 玩家1获胜

  • 玩家2获胜

  • 他们互相残杀(平局)

每个结果必须具有地区值,并且对于每种情况都必须始终相同。

例如:您可以1在玩家1获胜2时,玩家2获胜时以及0平局时输出。然后,您必须在玩家1获胜时,玩家2获胜时以及平局时始终输出。120

它可以返回或打印到标准输出。尾随空格很好。

显然,导致平局的唯一情况是两名球员都开火,并且双方都有弹药。

*由于在此挑战中,某人死亡后回合可能会继续,因此最终可能会有1个以上的玩家获胜。您需要根据输入查找谁先赢。

测试用例(假设1P1获胜,2P2获胜以及0平局):

"rg fr" => 1 (P1 shot P2 while they were reloading)

"rg ff" => 1 (They both shot, but only P1 had ammo)

"rr ff" => 0 (Both had ammo and shot each other)

"rr ff rr fg" => 0 (Both had ammo and shot each other. Everything after the first win is ignored)

"rr fg rf" => 2 (P2 shot P1 while they were reloading)

"rf gg rr fg rr fr" => 1
    (P2 tried to shoot but didn't have any ammo, then they both guarded, then they both reloaded, then P2 blocked a shot, then they both reloaded again [but P2 still only has 1 ammo!], then P1 shoots P2 while they're reloading.

"rr gf fr rf gg rg ff" => 1
       ^ Player 1 wins here. The rest to the right has no effect on the output

这是代码高尔夫,所以最少的字节数获胜!

注意,如测试用例所示,您必须处理“笨拙”的动作。对于没有弹药的玩家尝试射击或连续重新装满2回合(并且仅累积一个弹药),这是完全有效的。


我是否缺少某些东西,还是可以仅从上一回合确定输出?
xnor

@更新了问题。不会,因为您需要知道玩家是否有弹药。我意识到尽管您可以根据最后一轮的事实来假设哪个玩家拥有弹药。我实际上是在最后一分钟更改了规则,以允许假设某人死亡时输入将结束。我现在很后悔。
Carcigenicate's


3
这与为“加载,防御和射击”游戏得分非常相似。唯一的区别是,另一个挑战是枪支射击不止一次,而空枪射击被认为是作弊行为,并会丧失比赛资格。
丹尼斯,

我们可以为两个球员而不是回合提供两个单独的输入{"rff","rgf"}吗?
betseg

Answers:


2

视网膜,36字节

s`(?<=r..([^f]..)*)f
!
A`g
G1`!
\w
_

输入格式应为换行符分隔的对,例如

rr
fr

输出是!_玩家1获胜,_!如果玩家2获胜且!!有平局。

在线尝试!(为方便起见,使用空格分隔的测试套件。)

我一定完全忽略了这一挑战。我敢肯定,否则我会在Retina上尝试过。:)

说明

s`(?<=r..([^f]..)*)f
!

我们通过标记通过打开的第一个“有效”的拍摄开始f后各r!。我们通过匹配每个f可以找到r同一个玩家而不交叉的玩家来做到这一点fr通过始终同时搜索三个字符,可以轻松地将搜索限制在同一玩家上。

A`g

现在我们放弃所有有人守卫自己的回合,因为最后的回合不能是其中之一。

G1`!

现在我们保留第一个转弯,其中包含一个!。如果发生有效投篮(我们知道没有人守卫),则游戏结束。

\w
_

最后,我们需要合并字符串以提供一致的输出,我们只需将非!字符(rf)转换为即可_


5

Python,139字节

c=d=0
for i in input():
 b=(c&(i=='fr'))-(d&(i=='rf'));p,q=i
 if b|(i=='ff')&c&d:print b;break
 c,d=(p=='r',i!='fg')[c],(q=='r',i!='gf')[d]

以2个字符的字符串列表的形式在stdin上进行输入(例如['rf','rr','rg','ff'])。如果玩家1获胜,则输出1;如果玩家2获胜,则输出-1;对于平局,则输出0。

说明:首先检查是否有人发射了子弹,否则游戏结束。然后,我们确定玩家是否重装了枪支或浪费了弹药。

这是我的第一个Codegolf帖子:)


4

JavaScript(ES6),108 107 93 91 89 85字节

在Titus的帮助下节省了4个字节

将输入作为2个字符的字符串数组来描述每个玩家所玩的动作。

b=>b.map(c=>w=w||b&'312'[b=(s='0210231')[m='ffrfgrrggf'.search(c)]|s[m-2]&b,m],w=0)|w

返回值:

  • 1 如果玩家1获胜
  • 2 如果玩家2获胜
  • 3 抽签

怎么运行的

我们维护一个位掩码,以b描述谁拥有已加载的项目符号:

  • 位0:玩家1拥有一颗子弹
  • 位1:玩家2有一颗子弹

我们使用De Bruijn序列 'ffrfgrrggf'来识别所有9种可能的移动组合。我们使用OR和AND位掩码b根据移动组合进行更新。我们使用第三组与“与”在一起的位掩码b来确定获胜者w。(唯一3获胜组合是fffrrf)。

值得注意的是,OR和AND掩码可以以相同的模式存储,但要移位两个位置。

 Index in | Combination | Bullet   | Bullet  | Winner
 sequence |             | AND mask | OR mask | mask
----------+-------------+----------+---------+--------
    0     |     ff      |    0     |    0    |   3
    1     |     fr      |    0     |    2    |   1
    2     |     rf      |    0     |    1    |   2
    3     |     fg      |    2     |    0    |   0
    4     |     gr      |    1     |    2    |   0
    5     |     rr      |    0     |    3    |   0
    6     |     rg      |    2     |    1    |   0
    7     |     gg      |    3     |    0    |   0
    8     |     gf      |    1     |    0    |   0

测试用例


@Carcigenicate对于两个失败的案例,此问题均应修复。但是,在平局的情况下,我现在返回0(没有人被枪杀)或3(玩家互相杀死)。不知道是否允许。如果没有,我可以返回w%3
Arnauld

我希望每个方案1个输出。我保证尽管总有人会被枪杀,所以不必为这种情况而负责。导致平局的唯一情况是两人互相射击并且两人都有弹药。
Carcigenicate

&掩码可以为0 fr,rf,ff'312'['0210231'[m='ffrfgrrggf'.search(c)]|'233331'[m-3]&b]'123'['2100231'[m='frffgrrggf'.search(c)]|'233331'[m-3]&b]保存一个字节;但是他们工作吗?
泰特斯

@Titus有趣的是,在AND掩码之前应用OR掩码将适用于所有现有测试用例。但这将因为诸如此类的事情而失败["rr","fg","fr","rf"]
-Arnauld

&具有比更高的优先级|,因此更改顺序不应在那里进行任何更改(除了保存字节外)。但是我的代码中缺少该任务。尝试...'123'[b='2100231'...
泰特斯

2

Perl 6的71 62个字节

{&[<=>](|map {m/r[..[r|g]]*.$^f/.to//∞},/[r|f]f/,/.f[r|f]/)}

基于正则表达式的解决方案。

将输入作为字符串形式的形式"rg fr"
三种可能的输出是枚举值More(播放器1韩元), Less(播放器2韩元), Same(拉伸) -印刷时变成那些词语,或进入1-10当强制转换为数字。

在线尝试!

怎么运行的

  • map { m/r[..[r|g]]*.$^f/.to // ∞ }, /[r|f]f/, /.f[r|f]/

    在输入上执行两个正则表达式匹配。插值后,两个正则表达式为:

    • r[..[r|g]]*.[r|f]f –匹配玩家2的第一个成功射击。
    • r[..[r|g]]*..f[r|f] –匹配玩家1的第一个成功射击。

    在每种情况下,它都会返回匹配(.to)的结束位置;如果没有匹配,则返回无穷大。

  • &[<=>](|   )

    <=>运算符应用于两个匹配结束位置。它根据第一个参数是大于,小于还是等于第二个参数,从Order枚举(MoreLessSame)中返回一个值。


整齐。出于好奇,您如何键入无穷大符号?专用键盘,还是您键入alt + some number?您实际上是在通用的Perl代码中使用这样的字符,还是仅用于打高尔夫球?
Carcigenicate

@Carcigenicate:我的自定义键盘方案使我可以通过敲击四个键来输入它[Menu] i n f(这称为compose sequence)。但是,所有Perl 6符号都具有ASCII版本(例如Inf都是同义词),因此没有必要在Perl 6代码中使用Unicode符号。我就是喜欢... :)
短信

啊 关于Perl,这让我大跌眼镜的是无限符号。我认为这是一项要求,这似乎不必要地复杂。也许当我对Clojure感到无聊时,我会尝试Perl。最近我看了很多Perl代码。
Carcigenicate'2

@Carcigenicate:请注意,Perl 6基本上是一种新语言,与Perl不向后兼容,并且其解释器仍然很慢(对于某些功能,还存在许多错误)。当前版本为v5.24的Perl将继续单独维护。
smls

好,谢谢。很高兴知道。
Carcigenicate'2

2

Haskell101 91 87字节

n!(c:r)|'g'>c=n:1!r|'g'<c=1:0!r|1<3=2:n!r
_!r=[]
a#b=[x|x@(y,z)<-zip(1!a)$1!b,2>y+z]!!0

在线尝试!中缀函数#采用两个字符串来表示两个玩家各自的动作,(0,1)如果玩家1获胜,则返回(1,0)玩家2和(0,0)平局的字符串。

用法示例:

Prelude> "rgrfrf" # "fgrgrr"
(0,1)

说明:

中缀功能!将一系列动作'r'(重载),'f'(开火)和'g'(守卫)转换为一系列可观察到的动作0(实际开火),1(无动作)和2(后卫),其中开火动作仅算作实际开火动作如果装有子弹,则不执行任何操作。为了实现这一点,第一个参数n0是否装有子弹,以及1是否装有枪。这样,每个都'f'可以简单地用current代替n。(n=0->加载-> 实际射击 -> 0n=1->卸载-> 无动作 -> 1

n ! (c:r)                -- n is 0 or 1, c is 'f', 'g' or 'r' and r the rest of the string
    |'g'>c = n : (1 ! r) -- c is smaller 'g', so it must be 'f'. append n to the list
                         --  and set load status to 1 (unloaded)
    |'g'<c = 1 : (0 ! r) -- c is larger 'g', so it must be 'r'. append 1 (no action)
                         --  and set load status to 0 (loaded)
    |1<3   = 2 : (n ! r) -- c must be equal to 'g'. append 2 (guard)
                         --  and leave the load status unchanged
_ ! r = []               -- base case for recursion

然后是九种可能的结果

  • (0,0):双方射击并死亡,游戏结束。
  • (0,1)(1,0):一名玩家射击另一名,游戏结束。
  • (0,2)(2,0):一名球员投篮而另一名后卫继续比赛。
  • (1,1)(1,2)(2,1)(2,2):没有玩家射击,比赛继续进行。

通过设计,游戏结束选项的总和小于2,并且每个游戏持续可能性的总和大于或等于2。那么,游戏的结果就是第一个元组,其总和小于2。

a#b=[x|         -- build the list of all x
    x@(y,z) <-  -- where x is an alias for the tuple (y,z) which is drawn from the list
    zip (1!a)   -- of tuples where the first component is from 1!a = eg. [1,2,1,0,1,0] 
        (1!b)   -- and the second from 1!b = eg. [1,2,1,2,1,1]
    , 2 > y+z]  -- and y+z are smaller 2.
    !!0         -- return the first element of this list

1

批次,249个字节

@echo off
set g=goto gg
set/ax=y=0
:gg
shift&goto %1
:fg
set x=0
%g%
:gf
set y=0
%g%
:rr
set/ax=y=1
%g%
:fr
if %x%==1 exit/b1
:gr
set y=1
%g%
:rf
if %y%==1 exit/b2
:rg
set x=1
%g%
:ff
set/az=3-x-x-y
if %z%==3 %g%
exit/b%z%

每回合以成对字符形式输入,并按错误级别输出(0 =抽签,1 =玩家1,2 =玩家2)。xy跟踪玩家是否有弹药,因此,当双方都开火时,结果为3-x-x-y,除非为3,否则我们继续前进。在第5行中,我滥用了Batch的解析器- %1(这是当前的动作)在shift语句执行和删除之前被替换了,所以我们仍然转到正确的标签。


1

Clojure,168个字节

#(reduce(fn[[l L r R][a A]](if(and l L)(let[M(fn[r a A](if(and(= a \f)r)[nil(= A \g)][(or(= a \r)r)1]))[r L](M r a A)[R l](M R A a)][l L r R])[l L r R]))[1 1 nil nil]%)

少打高尔夫球(如果两个人都还活着,我们将使用M其更新弹药和敌人的生活状态,否则我们将返回当前状态):

(def f (fn[A] (reduce
                (fn [[l1 l2 r1 r2] [a1 a2]]
                  (if (and l1 l2)
                    (let[M (fn [r1 a1 a2]
                             (if (and(= a1 \f)r1)
                               [false (= a2 \g)]        ; we lost the ammo, a2 lives if he was guarding
                               [(or(= a1 \r)r1) true])) ; we might gain or keep ammo, a2 lives no matter what
                         [r1 l2] (M r1 a1 a2)
                         [r2 l1] (M r2 a2 a1)]
                      [l1 l2 r1 r2])
                    [l1 l2 r1 r2]))
                [true true false false] A)))

用法示例(第一个元素告诉玩家1是否在游戏结束时还活着,第二个元素告诉玩家2是否还活着,第3个和第4个元素告诉弹药状态,这与确定获胜者无关):

(-> (for[[a b s] (partition 3 "rr fg rf fr ")][a b]) f (subvec 0 2))

更新:好吧,它的loop长度是一样的!我发现reduce版本更易于开发,因为如果使用,您可以轻松检查中间状态reductions

#(loop[l 1 L 1 r nil R nil[[a A]& I]%](if(and l L)(let[M(fn[r a A](if(and(= a \f)r)[nil(= A \g)][(or(= a \r)r)1]))[r L](M r a A)[R l](M R A a)](recur l L r R I))[l L]))

我在等待!太好了,哇
Carcigenicate's

呵呵,谢谢,但它仍然让我很烦,我不得不重复[l1 l2 r1 r2](在其修改的值let和原来的值)和那些fn签名。
NikoNyrh

至少对于后者来说,这就是为什么我赞成loop。我发现它导致更整洁的代码。一旦我需要用1个以上的累加器折叠,我便进行切换。
Carcigenicate

1

PHP,107个 101 90字节

使用位掩码$ d表示加载状态,并使用DeBruijn序列进行射击。

for(;!$x=$d&strpos(_frff,$m=$argv[++$i]);)$d=$d&g<$m|h<$m|2*($d/2&f<$m[1]|g<$m[1]);echo$x;

将输入作为2个字符的命令行参数,并使用运行-nr

1 =玩家1获胜
2 =玩家2获胜
3 =平局

分解

for(;!$x=$d&strpos(_frff,       // 1. $x=someone dies, loop while not
    $m=$argv[++$i]          // loop throug moves
);)
    $d=
        $d&g<$m|h<$m            // 2. unload/reload Player 1 = bit 0
    |2*(
        $d/2&f<$m[1]|g<$m[1]    // 3. unload/reload Player 2 = bit 1
    );
echo$x;
  • DeBruijn序列::frposition = 1 = P1发射;rf=位置2 = P2射击,ff=位置3 =两者都射击
  • g<$m<=> f<$m[0]f<$m始终为true,因为有第二个字符)。

0

Python,200个字节

def war_game(turns):
    turn=0
    player1=True
    player2=True
    ammo1=False
    ammo2=False
    while turn<len(turns):
        if turns[turn][0]=='f' and ammo1==True and turns[turn][1]!='g':
            player2=False
        elif turns[turn][0]=='f' and turns[turn][1]=='g':
            ammo1=False
        elif turns[turn][0]=='r':
            ammo1=True
        if turns[turn][1]=='f' and ammo1==True and turns[turn][0]!='g':
            player1=False
        elif turns[turn][1]=='f' and turns[turn][0]=='g':
            ammo2=False            
        elif turns[turn][1]=='r':
            ammo2=True
        if player2==False or player1==False:
            break
        turn+=1
    if player1==True and player2==False:
        print('Player 1 wins')
        return 1
    elif player1==False and player2==True:
        print('Player 2 wins')
        return 2
    print('Draw')
    return 0

2
欢迎来到该网站。比赛以字节数计分,因此我建议您在标题中添加字节数,并尝试通过减少变量名的长度来使其最小化。您还应该包括以其编写的语言(在我看来像Python3)。
发布Rock Garf Hunter '02

2
如上所述,这是一个竞赛,可以制定尽可能小的程序来完成任务。您使用的是全名,例如,turns而不是just t,这意味着程序比所需的大得多。另外,请以类似以下内容#Python 2, 200 bytes(假设为2,程序长度为200字节)开始提交,这样您所使用的语言就清晰了。
Carcigenicate'2

0

Clojure中,180个 173字节

(fn[t](loop[z nil x nil[[c v]& r]t](let[k #(and %3(= %\f)(not= %2\g))h #(and(not= %\f)(or %2(= %\r)))q(k v c x)w(k c v z)](cond(and q w)0 q 2 w 1 1(recur(h c z)(h v x)r)))))

通过将功能更改为完整功能而不是使用宏来获得-7个字节。这使我可以创建内部函数宏,从而节省了一些时间。

这是一个非常实际的解决方案。因为我只是写了完整版的游戏,所以我心不在mind,这基本上是我使用的算法的简化版本。我可能可以做很多优化,但是我对此很满意。请参阅预先编写的代码以获取解释。

(defn outcome [turns] ; Take input as ["rr" "ff"]
  (loop [p1-ammo? false ; Keep track of if each player has ammo
         p2-ammo? false
         [[p1-move p2-move] & rest-turns] turns] ; Deconstruct the turns out

    (let [killed? (fn [m m2 a] (and a (= m \f) (not= m2 \g))) ; Function that checks if one player killed the other
          has-ammo? (fn [m a] (and (not= m \f) (or a (= m \r)))) ; Function that decides if a player has ammo in the
                                                                 ;  next turn
          p1-killed? (killed? p2-move p1-move p2-ammo?) ; Check if each player was killed.
          p2-killed? (killed? p1-move p2-move p1-ammo?)]

      (cond ; Check who (if any) died. If no one died, recur to next turn.
        (and p1-killed? p2-killed?) 0
        p1-killed? 2
        p2-killed? 1
        :else (recur (has-ammo? p1-move p1-ammo?)
                     (has-ammo? p2-move p2-ammo?)
                     rest-turns)))))
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.