Ви можете виграти ще двома рухами у «Трьох чоловіків Морріс»?


16

Bounties

№ 1 ( нагороджено )

Я закину 50 реп. За першу правильну відповідь

№ 2 ( нагороджено )

Я підкину ще 100 повторень для найкоротшої вірної відповіді.

№ 3 ( відкрито для подання )

Я закину 200 повторень за першу зі значно коротшою достовірною відповіддю. Значне значення становить не більше 45% від найкоротшої відповіді на даний момент ( 564 байт х 0,45 = макс. 254 байти ).


Гра

Ви пам’ятаєте класичну гру « Дев'ять чоловіків Морріс » чи просто « Млин »? Існує варіант під назвою Три чоловіки Морріса, який трохи схожий на змінний тик-носок.

Правила

Це порожня дошка гри:

   a   b   c
1 [ ]–[ ]–[ ]
   | \ | / |
2 [ ]–[ ]–[ ]
   | / | \ |
3 [ ]–[ ]–[ ]

[ ]є полем і |–/\представляють маршрути між цими полями.

У гру грають два гравці 1і 2кожен розміщує по 3 жетони на дошці. Це насправді вже відбулося, і ми в грі. Гра виграється, якщо один гравець може сформувати a, millякий є вертикальним або горизонтальним рядом з 3 жетонів гравця.

Токени можна переміщувати на дошці по сполучних лініях, згідно з цим правилом:

До будь-якого сусіднього порожнього положення (тобто від краю краю до центру, або від центру до крайового положення, або від крайового до суміжного крайового положення

Гравець повинен зробити хід, якщо немає сусідньої порожньої позиції, і в цьому випадку хода пропускається.

Змагання

Ти гравець, 1і твій крок наступний. Напишіть програму або функцію, яка визначає:

  • ви можете примусити виграш за допомогою двох та менших рухів ( певний виграш )
  • Ви можете виграти з 2 або меншими ходами, якщо ваш опонент помилиться ( можлива перемога )
  • ви не можете виграти з двома та меншими рухами, тому що вам потрібно більше рухів або тому, що вимушені рухи приводять опонента до перемоги ( неможливо перемогти )

Вимоги

  • Незважаючи на те, що ви безумовно виграєте, коли ви розгромили опонента на смерть, ваша програма повинна закінчитися в обмежений час.
  • Можна написати програму або функцію.

Вхідні дані

Гравці представлені 1і 2. 0визначає вільне поле. Ви можете приймати введення як матриця або масив.

Певне

A         B         C         D
2 1 0  |  2 1 0  |  1 0 1  |  1 2 2
2 1 2  |  0 1 0  |  1 0 2  |  2 1 O
0 0 1  |  2 2 1  |  0 2 2  |  O O 1

A: [2,1,0,2,1,2,0,0,1]
B: [2,1,0,0,1,0,2,2,1]
C: [1,0,1,1,0,2,0,2,2]
D: [1,2,2,2,1,0,0,0,1]

Можливо

A         B         C
1 0 1  |  1 0 1  |  1 2 2
1 2 2  |  1 2 0  |  0 0 1
2 0 0  |  2 0 2  |  2 1 0

A: [1,0,1,1,2,2,2,0,0]
B: [1,0,1,1,2,0,2,0,2]
C: [1,2,2,0,0,1,2,1,0]

Неможливо

A         B    
1 0 0  |  1 2 0
1 2 2  |  2 1 0
2 0 1  |  1 2 0

A: [1,0,0,1,2,2,2,0,1]
B: [1,2,0,2,1,0,1,2,0]

Вихідні дані

Ваша програма повинна вивести / повернути смайлик:

  • Визначальний виграш: :)
  • Можливий виграш: :|
  • Перемогти неможливо: :(

Приклади

Визначна перемога в два ходи:

[2][1][ ] 1. [2][1][ ]
[2][1][2] -> [2][1][2]
[ ][ ][1]    [ ][1][ ]

[2][1][ ] 1. [2][1][ ]    [ ][1][ ] 2. [ ][ ][1]
[ ][1][ ] -> [ ][ ][1] -> [2][ ][1] -> [2][ ][1]
[2][2][1]    [2][2][1]    [2][2][1]    [2][2][1]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][ ][2] -> [1][ ][2] -> [1][ ][2] -> [ ][ ][2]
[ ][2][2]    [ ][2][2]    [2][ ][2]    [2][ ][2]

Можлива перемога в два ходи:

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][2][2] 1. [ ][2][2]    [2][ ][2] 2. [1][2][2]
[ ][ ][1] -> [1][ ][1] -> [1][ ][1] -> [1][1][1]
[2][1][ ]    [2][1][ ]    [2][1][ ]    [2][ ][ ]

Виграти неможливо двома ходами:

[1][ ][ ]
[1][2][2]
[2][ ][1]

Бонус

Якщо можливий певний виграш і ваша програма виводить ходи в один бік до успіху, як a1:a2(1 хід) або a1:a2,a3:b2(2 ходи), ви можете зняти 30% від кількості байтів.


Це кодовий гольф - тому найкоротша відповідь у байтах виграє. Стандартні лазівки заборонені.


Завдяки Пітеру Тейлору, який виправив деякі недоліки та покращив формулювання в « Пісочниці» .



1
Мені подобаються ці таблиці ascii / graphics =)
flawr

1
Що станеться, якщо гравець не може рухатися? наприклад [1,0,0,2,1,0,2,2,1], гравець 2 не може рухатися - це виграш для гравця 1?
VisualMelon

1
@LeifWillerts Я можу нерозуміти, що ви маєте на увазі, але в такому випадку жоден гравець не перебуває у виграшному стані - вони виграють лише шляхом горизонтальної чи вертикальної лінії (не діагоналі).
VisualMelon

3
Ну, є лише 1680 дійсних позицій плати, тому жорстке кодування може дати трохи більше 210 байт. (менше, якщо розглядати симетрію)
ліртосіаст

Відповіді:


1

Haskell, 580 564 441 байт

Це те, наскільки я зараз можу пограти в гольф. Не впевнений, чи можуть інші мови перемогти його.

Зателефонуйте mдо списку на кшталт списку [[2,1,0],[2,1,2],[0,0,1]](напевно A).

import Data.Array
r=[0..2]
p?f=[(x,y)|x<-r,y<-r,f!y!x==p]
p%f=all(==x)xs||all(==y)ys where(x:xs,y:ys)=unzip$p?f
s p x y f=f//[(y,f!y//[(x,p)])]
p#f=[s 0 x y$s p u v f|a@(x,y)<-p?f,b@(u,v)<-0?f,((x-u)*(y-v)==0&&abs(x+y-u-v)==1)||elem(1,1)[a,b]]
p&f|p#f>[]=p#f|0<1=[f]
e=any
i a p f=e(a$e(p%))(map(map(p&))(map((3-p)&)$p&f))||e(p%)(p&f)
l=listArray(0,2)
f(True,_)=":)"
f(False,True)=":|"
f _=":("
m=putStrLn.f.(\f->(i all 1 f,i e 1 f)).l.map l

Код тесту:

da = [[2,1,0],[2,1,2],[0,0,1]]
db = [[2,1,0],[0,1,0],[2,2,1]]
dc = [[1,0,1],[1,0,2],[0,2,2]]
dd = [[1,2,2],[2,1,0],[0,0,1]]
pa = [[1,0,1],[1,2,2],[2,0,0]]
pb = [[1,0,1],[1,2,0],[2,0,2]]
pc = [[1,2,2],[0,0,1],[2,1,0]]
ia = [[1,0,0],[1,2,2],[2,0,1]]
ib = [[1,2,0],[2,1,0],[1,2,0]]
al = [da,db,dc,dd,pa,pb,pc,ia,ib]

mapM_ m al повертає:

:)
:)
:)
:)
:|
:|
:|
:(
:(

1
Виправлено, я думаю. Буде двічі перевіряти та правильно грати в гольф увечері (що ось до закінчення пільгового періоду)
Leif Willerts

5

C # - 739 663 байти

Повна програма, читає введення з argv і, здається, працює. Виконайте це як

ThreeMill 1 2 1 1 2 0 0 0 2

Якщо цей спосіб введення неприйнятний, я буду радий змінити його (ніколи не люблю використовувати argv).

using System;using System.Linq;class P{static void Main(string[]A){var I=new[]{0,3,6,1,4,7,2,5,8};Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" ";Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0;Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I.Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))).Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;})).DefaultIfEmpty(B).ToArray();int h,G;Console.WriteLine(":"+"(|))"[V(A,"1").Max(z=>((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0)+(h>G?W(z,"1")*2:2))]);}}

Мені вчора було відмовлено в опублікуванні цього запису, тому що мені не вдалося багато пограти в нього (не було всього стільки часу, і я, можливо, був поза практикою), але оскільки відповіді ще не було, я ' Я все-таки опублікую це, я, звичайно, не чекаю щедрості, я б швидше пішов до того, хто доклав трохи більше зусиль до їхнього розміщення!

Редагувати: замінив усі булі на ints, що означало, що я можу краще використовувати Linq, і мені вдалося згортати обидва петлі foreach, даючи великі заощадження. Я трохи вражений, що hлічильник працює ... ++ - така тонка утиліта.

Програма дуже проста, вона просто досліджує всі можливі набори ходів (зберігає стан дошки в рядку []). Він повторює всі наші можливі кроки (дошки, які є результатом цього), і підраховує кількість відповідей опонента, які ми можемо успішно перемогти ( G) (тобто ті, які ми виграємо, а він ні). Він також підраховує кількість можливих відповідей (h). Якщо ми можемо виграти будь-який, то це можливо, і ми додаємо 1 до суми, якщо ми зможемо їх все виграти, це визначено, і ми додаємо 2 до суми. Тому максимум - це наш найкращий результат, і ми індексуємо в рядок "(|))", щоб повернути відповідне обличчя. Зауважте, що нам потрібна додаткова ")", тому що сума може бути 2 або 3, якщо це визначено (можливо, ми не можемо перемогти жодних відповідей, які вже виграли в першому ході, тому можлива перевірка: введення в оману).

Програма перевіряє перемогу, створюючи рядок із дошки, тобто розділених пробілом рядків і стовпців, і просто шукає рядок з 3-х символів гравця в цій рядку (наприклад, "201 201 021 220 002 111" - це виграти для нас)

using System;
using System.Linq; // all important

class P
{
    static void Main(string[]A) // transform to int?
    {
        var I=new[]{0,3,6,1,4,7,2,5,8}; // vertical indexes
        Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" "; // joins the strings up, so that there is a space separating each group of three (including at end)
        Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0; // checks if a particular player wins
        Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I // for each imagineable move
            .Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))) // where it's legal
            .Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;}) // select the resulting board
        ).DefaultIfEmpty(B) // allow not-moving
        .ToArray();

        int h, // h stores the number of responses the opponent has to each move
        G; // G stores the number of responses by the opponent we can beat

        Console.WriteLine(":"+"(|))"[ // we index into this to decide which smiley
            V(A,"1").Max(z=>
                    ((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0) // if there is atleast 1 reponse by the opponent we can beat, we can possibly win
                    +(h>G?W(z,"1")*2:2) // if there are moves which we can't win, then if we have already won (one-move), else, we can definitely win
                   ) // sum is therefore 0 if impossible, 1 if possible, >2 (no more than 3) if definite 
            ]);

    }
}

Ось мій тестовий сценарій:

ThreeMill 2 1 0 2 1 2 0 0 1
ThreeMill 2 1 0 0 1 0 2 2 1
ThreeMill 1 0 1 1 0 2 0 2 2
ThreeMill 1 2 2 2 1 0 0 0 1

ThreeMill 1 0 1 1 2 2 2 0 0
ThreeMill 1 0 1 1 2 0 2 0 2
ThreeMill 1 2 2 0 0 1 2 1 0

ThreeMill 1 0 0 1 2 2 2 0 1
ThreeMill 1 2 1 1 2 0 0 0 2
ThreeMill 1 0 1 2 0 2 1 0 2

Які виходи

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)

Приємно. Дякуємо, що ви були першими. :) Якщо це нормально, я нагороджую винагороду після вихідних, щоб залишити її ще кілька днів на вкладці "Популярні".
insertusernamehere

@insertusernamehere Це добре мені, якщо я не можу заважати робити якусь справжню роботу, завтра я можу зробити ще якусь роботу над цим.
VisualMelon

1
Це нагадує мені цей коментар: " Я не зміг відповісти на запитання за FORTY MINUTES. Це критично! Просто надішліть деталі бази даних, і я вставлю SQL свої відповіді. У мене так багато роботи, щоб уникнути і без причин щоб уникнути цього !! "на" Чому переповнення стека не працює? . :)
вставитикористувач туди

1

PowerShell 576 550 байт

Мене не буде так легко стримувати - якщо я не можу отримати C # нижче 631 байта, мені доведеться замість цього використовувати іншу мову! Я сподіваюся, що Лейф Віллертс вирве на 5 байт свою відповідь, тому що я вирішив, що не надто люблю PowerShell, можливо, мені просто потрібно на це об'єктивно подивитися на кількість байтів ...

Це сценарій, ви його запустите . .\mill.ps1 "201102021" . Це досить добре копія моєї відповіді C #, лише мовою, з якою я мало досвіду. Я не доклав надто великих зусиль для того, щоб пограти в гольф, тому що для того, щоб попрацювати в першу чергу, знадобилося так довго, і це вже досить компактно.

Редагувати: не вдалося залишити ці [Math]::Floorдзвінки там

param($U);$I=0,3,6,1,4,7,2,5,8;function J($S){($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}function W($D,$p){(J $D)-or(J $D[$I])}function V($Q,$C){$I|%{$a=$_;$I|?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}|%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}|%{$n=1}{$n=0;$_}{if($n){$Q}}}$e=$f=0;V $U "1"|%{$h=0;$x=$_;V $x "2"|%{$k=0;(V $_ "1"|%{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k};if($h-eq0-or(W $x "1")){$f=2}};":"+"(|))"[$e+$f]

Якщо ви описуєте, як це працює ... відповідь C # призначена для вас, але, сподіваємось, коментарі чітко дають зрозуміти. Точки з комою можуть не збігатися з однорядковою командою, я ще не впевнений, де вони потрібні та ні, і не скопіював їх назад, коли я ставлю всю справу в один рядок.

param($U); # take input as argument

$I=0,3,6,1,4,7,2,5,8; # cols

function J($S){ # checks if this is a winning string
($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}

function W($D,$p){ # checks if this is a winning board
(J $D)-or(J $D[$I])} # $D[$I] reorganises into columns

function V($Q,$C){ # yields all valid moves from position $Q for player $C
$I|%{$a=$_;$I| # for each possible move
?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}| # where legal
%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}| # make the move (copy $Q to an array, modify, join into a string)
%{$n=1}{$n=0;$_}{if($n){$Q}}} # if empty, return $Q - I am confident this can be achieved with commas, and [0], and maybe a +, but I don't want to think about it

$e=$f=0; # possible, definite

V $U "1"|%{ # for all our possible moves
$h=0;$x=$_; # $k is whether we win all of these
  V $x "2"| # for all opponent's responses
  %{$k=0;(V $_ "1"| # for all our responses
  %{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k}; # if we can win and he can't, then things are looking good, set $e to 1 (possible win)

  if($h-eq0-or(W $x "1")){$f=2} # if we win every move, or we have already won, it's a definite
};

":"+"(|))"[$e+$f] # smile, it's all over

Тестовий сценарій (PowerShell):

. .\mill.ps1 "210212001"
. .\mill.ps1 "210010221"
. .\mill.ps1 "101102022"
. .\mill.ps1 "122210001"

. .\mill.ps1 "101122200"
. .\mill.ps1 "101120202"
. .\mill.ps1 "122001210"

. .\mill.ps1 "100122201"
. .\mill.ps1 "121120002"
. .\mill.ps1 "101202102"

. .\mill.ps1 "100122201"
. .\mill.ps1 "120210120"

Вихід:

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
:(
:(

1

Python 3, 566 557 байт

Мені доведеться побачити, чи зможу я ще більше пограти в гольф, чи я можу отримати 30% бонус, але після довгого зволікання ось моя відповідь.

def t(g,x=1,r=0,z=0):
 m=[[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]];a=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];z=z or[[],[],[],[]];s=0
 if r>3:return z
 for i in a:
  if g[i[0]]==g[i[1]]==g[i[2]]>0:s=g[i[0]];break
 z[r]+=s,
 for q in range(9):
  i=g[q]
  if i==x:
   for p in m[q]:
    if g[p]<1:n=g[:];n[q],n[p]=n[p],n[q];z=t(n,3-x,r+1,z)
 if r:return z
 else:
  w=l=0
  for j in range(4):w=w or 1in z[j];l=l or 2in z[j]
  if l<1and w:return":)"
  elif w<1and l:return":("
  else:return":|"

Безголівки:

def three_mens_morris(grid, player=1, rec=0, w_l=0, p=0):
    moves = [[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]]
    w_l = w_l or [[],[],[],[]]
    if rec == 4: return w_l
    result = check_grid(grid)
    w_l[rec].append(result)
    for sq_1 in range(len(grid)):
        piece = grid[sq_1]
        if piece == player:
            for sq_2 in moves[sq_1]:
                if grid[sq_2] == 0:
                    new_grid = grid.copy()
                    new_grid[sq_1],new_grid[sq_2]=new_grid[sq_2],new_grid[sq_1]
                    w_l = three_mens_morris(new_grid,3-player,rec+1,w_l)
    if p: print(w_l)
    if rec:
        return w_l
    else:
        win = loss = 0
        for i in range(4):
            if 1 in w_l[i]:
                win = 1
            elif 2 in w_l[i]:
                loss = 1
        if p:print(win,loss)
        if loss==0 and win:
            return ":)"
        elif loss and win==0:
            return ":("
        else:
            return ":|"

def check_grid(grid):
    rows = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
    for i in rows:
        if grid[i[0]]==grid[i[1]]==grid[i[2]] and grid[i[0]]:
            return grid[i[0]]
    return 0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.