Найти результат игры войны


15

Найти результат игры войны

Когда я учился в начальной школе, была игра «Каменные ножницы», в которую мы играли во время собраний, в ожидании учителя, на переменах и т. Д. Мы называли это «Войной». Однако после некоторого поиска выясняется, что это гораздо более простой вариант «игры с дробовиком» (согласно WikiHow) . Я собираюсь назвать это «Войной», так как правила немного отличаются:

2 человека сидят напротив друг друга. Цель игры - «убить» другого игрока. Каждый ход вы можете сыграть один из 3 ходов:

  • Перезагрузка : у вас есть пистолет, который держит один выстрел. Это должно быть перезаряжено прежде, чем это может быть запущено каждый раз. Перезагрузка, когда у вас уже есть боеприпасы, законна, но ничего не делает. Перезагрузка была символизирована постукиванием по храму обеими руками. Каждый игрок начинает с 0 патронов.

  • Охрана : единственный безопасный ход. Если вы стреляете во время охраны, вы не умрете. Символом охраны было скрещивание рук на груди.

  • Огонь : стрелять из пистолета. Чтобы успешно стрелять, вы должны перезагрузить с момента последнего выстрела. Если ваш противник перезагружается, вы выигрываете. Если они тоже стреляют, и у вас обоих есть патроны, это ничья. Если они охраняют, вы потратили впустую боеприпасы. Хотя стрельба без боеприпасов - законный ход, он ничего не делает и оставляет вас уязвимыми, как перезарядка. Стрельба была символизирована указанием на другого игрока.

Игра была похожа на RPS, в которой каждый игрок одновременно отказывался от своего выбора (мы постукивали по ногам дважды между поворотами, чтобы поддерживать ритм друг с другом, но это не важно для вызова).

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

Ваша задача - найти результат игры War. Это может быть функция или полная программа.

вход

  • Опция, которую каждый игрок выбрал каждый ход, будет представлена ​​символом / строкой:

    • r : перезагрузить

    • г : охранник

    • ф : огонь

  • Входными данными будут список пар, строка с разделителями / неограниченной линией или что-либо еще в этих строках.

Пример ввода в Python может быть следующим: [("r", "g"), ("f", "r")]первый игрок перезагружается, а второй игрок охраняется. Во второй ход первый игрок стреляет, а второй перезагружается. Первый игрок выигрывает в этой игре. Же вход может необязательно быть представлена в виде "r g f r", "rgfr", "rg fr" "rg-fr"...

Вы можете предположить следующее:

  • Ввод будет соответствовать выбранному вами формату и будет содержать только допустимые символы.

  • Кто-то умрет в течение 100 ходов.

Однако вы не можете предполагать, что ходы заканчиваются, когда кто-то умирает.

Выход

Значение, указывающее, кто победил (или кто победил первым *). Вы можете выбрать, что выводить для каждого сценария, но должны учитывать следующее:

  • Игрок 1 выигрывает

  • Игрок 2 выигрывает

  • Они убивают друг друга (рисуют)

Каждый результат должен иметь значение района и всегда должен быть одинаковым для каждого сценария.

В качестве примера: вы можете выводить, 1когда игрок 1 выигрывает, 2когда игрок 2 выигрывает, и 0в случае ничьей. Затем вы должны всегда выводить, 1когда игрок 1 выигрывает, 2когда игрок 2 выигрывает, и 0в случае ничьей.

Его можно вернуть или распечатать на стандартный вывод. Задний пробел в порядке.

Ясно, что единственный сценарий, который приводит к ничьей, - это если оба игрока стреляют, и у обоих есть патроны.

*Поскольку в этом вызове ходы могут продолжаться после смерти, возможно, в конечном итоге выиграет более 1 игрока. Вам нужно найти, кто победил первым по входу.

Тестовые случаи (при условии, 1когда выигрывает P1, 2когда выигрывает P2 и 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


3
Это очень похоже на Оценка игры Load, Defend and Shoot . Единственное отличие состоит в том, что в другом вызове есть орудия с более чем одним выстрелом, и что стрельба из пустого ружья считается мошенничеством и утрачивает игру.
Деннис

Можем ли мы взять два отдельных входа для двух игроков вместо раундов, например {"rff","rgf"}?
Betseg

Ответы:


2

Сетчатка , 36 байт

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

Формат ввода должен быть парами, разделенными переводом строки, например

rr
fr

Выход - !_игрок 1 выигрывает, _!если игрок 2 выигрывает, и !!если есть ничья.

Попробуйте онлайн! (Набор тестов, который использует пробел для удобства.)

Должно быть, я полностью упустил этот вызов. Я уверен, что я бы попробовал это в Retina ранее, в противном случае. :)

объяснение

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

Мы начинаем с маркировки «действительных» снимков, превращая первый fпосле каждого rв !. Мы делаем это путем сопоставления каждого fиз которых может найти одного и rтого же игрока, не пересекая другого f. Ограничить поиск до rs на одном и том же игроке легко, всегда набирая по три символа за раз.

A`g

Теперь мы отбрасываем все ходы, в которых кто-то охранял себя, потому что конечный ход не может быть одним из них.

G1`!

Теперь мы сохраняем только первый ход, который содержит !. Если действительный выстрел случается (и мы знаем, что никто не охраняется), игра заканчивается.

\w
_

Наконец, нам нужно объединить строку, чтобы получить согласованные выходные данные, и мы просто делаем это, превращая не- !символы (или, rили f) в _.


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]

Вводит ввод в stdin в виде списка 2-символьных строк (например, ['rf', 'rr', 'rg', 'ff']). Выводит 1, если игрок 1 выигрывает, -1, если игрок 2 выигрывает, и 0 для ничьей.

Пояснение: Сначала проверяется, стрелял ли кто-нибудь из пуль, если это так, игра заканчивается. Затем мы определяем, перезаряжали ли игроки свое оружие или впустую тратят боеприпасы.

Это мой первый пост Codegolf :)


4

JavaScript (ES6), 108 107 93 91 89 85 байт

Сохранено 4 байта с помощью Тита

Принимает ввод в виде массива из двухсимвольных строк, описывающих ходы, сыгранные каждым игроком.

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 есть пуля

Мы используем последовательность Де Брюина 'ffrfgrrggf' для определения всех 9 возможных комбинаций ходов. Мы используем битовые маски OR и AND для обновления в bсоответствии с комбинацией перемещений. Мы используем 3-й набор битовых масок, которые используются bдля определения победителя w. (Только три выигрышные комбинации быть ff, frи rf.)

Стоит отметить, что маски 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.
Арно

Я хотел 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 Интересно, что применение маски OR перед маской AND будет работать для всех существующих тестовых случаев. Но это потерпит неудачу из-за чего-то вроде["rr","fg","fr","rf"]
Арно

&имеет более высокий приоритет, чем |, поэтому изменение порядка не должно ничего менять (кроме сохранения байта). Но назначение отсутствовало в моем коде. Попробуй ...'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 Won), Less(игрок 2) вон, Same(рисовать) - которые превращаются в эти слова при печати, или в 1, -1, 0когда принуждают к номерам.

Попробуйте онлайн!

Как это устроено

  • 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.

    В каждом случае он возвращает конечную позицию match ( .to) или бесконечность, если совпадений не было.

  • &[<=>](|   )

    Применяет <=>оператор к двум конечным позициям совпадения. Возвращает значение из Orderперечисления ( More, Lessили Same) в зависимости от того, больше ли первый аргумент, меньше или равен второму.


Ухоженная. Из любопытства, как вы печатаете символ бесконечности? Специальная клавиатура или вы набираете alt + some number? И действительно ли вы используете такие символы в обычном коде Perl или это только для игры в гольф?
Carcigenicate

@Carcigenicate: Моя настроенная схема клавиатуры позволяет мне вводить ее, нажимая четыре клавиши [Menu] i n f(это называется последовательностью составления ). Однако все символы Perl 6 имеют версии ASCII - например, Infи являются синонимами - поэтому нет необходимости использовать символы Unicode в коде Perl 6. Мне просто нравится ... :)
smls

Ааа. В Perl меня бросила одна вещь - символ бесконечности. Я думал, что это требование, которое казалось излишне сложным. Возможно, когда мне надоест Clojure, я попробую Perl. В последнее время я видел много кода на Perl.
Carcigenicate

@Carcigenicate: имейте в виду, что Perl 6 - это по сути новый язык, который не обратно совместим с Perl, и его интерпретатор все еще медленный (а для некоторых функций глючит). Perl, в настоящее время версия v5.24, продолжает поддерживаться отдельно.
smls

Хорошо спасибо. Хорошо знать.
Carcigenicate

2

Haskell , 101 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(охрана), где действие огня считается только фактическим действием огня. если пуля заряжена, и в противном случае никаких действий не предпринимается . Для этого первым аргументом nявляется 0то, заряжена 1ли пуля и не заряжена ли пушка. Таким образом, каждый 'f'может быть просто заменен текущим n. ( n=0-> загружено -> фактический пожар -> 0, n=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). xи yследите за тем, есть ли у игрока боеприпасы, поэтому, когда оба выстрела, результат будет 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

Хе-хе, спасибо, меня все еще раздражает, что мне пришлось повторить [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 fr:: position = 1 = P1 срабатывает; rf= позиция 2 = ffстрельба P2, = позиция 3 = оба огня
  • g<$m<=> f<$m[0]( f<$mвсегда верно, потому что есть второй символ).

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 для меня).
Пост Рок Гарф Хантер

2
Как упомянуто выше, это соревнование, которое может сделать самую маленькую программу, способную выполнить задачу. Вы используете полные имена как turnsвместо просто t, что означает, что программа намного больше, чем необходимо. Также, пожалуйста, начните с чего-то вроде #Python 2, 200 bytes(при условии, что это 2, а длина программы 200 байт), чтобы язык, который вы используете, был понятным.
Carcigenicate

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 байт, изменяя функцию на полную функцию вместо использования макроса. Это позволило мне сделать макросы внутренних функций, что немного экономит.

Это очень буквальное решение. Я схожу с ума, так как я только что написал полную версию игры, и это в основном сильно урезанная версия алгоритма, который я использовал. Вероятно, я мог бы сделать много оптимизаций, но я вполне доволен этим. См. Pregolfed код для объяснения.

(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)))))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.