Three Men's Morris'de iki hamle daha kazanabilir misin?


16

İkramiyeleri

1 numara ( ödüllü )

İlk geçerli cevap için 50 temsilci atacağım

2 ( ödüllü )

En kısa geçerli cevap için 100 tekrar daha atacağım.

3 ( gönderime açık )

Birincisi için 200 temsilciyi daha kısa bir geçerli cevapla atacağım. Şu anda en kısa yanıtın en fazla% 45'i önemlidir ( 564 byte x 0.45 = max 254 byte ).


Oyun

Klasik oyun " Dokuz Erkekler Morris " veya sadece " Değirmen " hatırlıyor musunuz? Üç Erkekler Morris adında , değişebilir bir tic-tac-toe gibi bir varyasyon var .

kurallar

Bu oyunun boş tahtası:

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

[ ]bir alandır ve |–/\bu alanlar arasındaki yolları temsil eder.

Oyun iki oyuncu tarafından oynanır 1ve 2her biri tahtaya 3 jeton yerleştirir. Bu aslında zaten oldu ve biz oyundayız. Bir oyuncu mill, oyuncunun 3 jetonunun dikey veya yatay sırası olan bir oyuncu oluşturabilirse oyun kazanılır .

Jetonlar, bu kurala göre bağlantı çizgileri boyunca tahta üzerinde hareket ettirilebilir:

Bitişik boş bir konuma (yani kenar konumundan merkeze veya merkezden kenar konumuna veya kenar konumundan bitişik kenar konumuna)

Bir oyuncu bitişik boş pozisyon olmadığı sürece bir hamle yapmalıdır, bu durumda hamle atlanır.

Meydan okuma

Siz oyuncusunuz 1ve hamleniz sırada. Aşağıdakileri yapıp yapmadığını belirleyen bir program veya işlev yazın:

  • kazanmayı 2 veya daha az hamle ile zorlayabilirsiniz ( kesin kazanç )
  • Rakibiniz hata yaparsa 2 veya daha az hamle kazanabilirsiniz ( olası kazanç )
  • 2 ya da daha az hamle kazanamazsınız çünkü daha fazla hamleye ihtiyacınız olacak ya da zorla hamle rakibinizin kazanmasına neden olacak (kazanmak imkansız )

Gereksinimler

  • Rakibinizi ölüme götürdüğünüzde kesinlikle kazanmanıza rağmen, programınızın sınırlı bir sürede bitmesi gerekir.
  • Bir program veya işlev yazabilirsiniz.

Giriş

Oyuncu tarafından temsil edilir 1ve 2. 0Serbest bir alanı tanımlar. Girdiyi bir matris veya dizi olarak alabilirsiniz.

kesin

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]

Mümkün

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]

imkansız

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]

Çıktı

Programınız bir gülen yüz çıkarmalı / döndürmelidir:

  • Kesin kazanç: :)
  • Olası kazanç: :|
  • Kazanmak imkansız: :(

Örnekler

İki hamlede kesin kazanç:

[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]

İki hamlede olası kazanç:

[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][ ][ ]

İki hamlede kazanmak imkansız:

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

Bonus

Belirli bir kazanmanın mümkün olması ve programınızın a1:a2(1 hamle) veya a1:a2,a3:b2(2 hamle) gibi bir yoldan başarıya hamle çıkarması durumunda, bayt sayınızın % 30'unu geri çekebilirsiniz .


Bu kod golf - bayt çok kısa cevap kazanır. Standart boşluklara izin verilmez.


Sayesinde Peter Taylor bazı kusurları ve geliştirilmiş ifadeler sabit Sandbox .



1
Bu ascii tablolarını / grafiklerini seviyorum =)
flawr

1
Bir oyuncu hareket edemezse ne olur? Örneğin [1,0,0,2,1,0,2,2,1], 2. oyuncu hareket edemez - bu 1. oyuncu için bir kazanç mıdır?
VisualMelon

1
@LeifWillerts Ne demek istediğinizi yanlış anlamış olabilirim, ancak bu durumda hiçbir oyuncu kazanan durumda değildir - sadece yatay veya dikey bir çizgiye (çapraz değil) sahip olarak kazanırlar.
VisualMelon

3
Sadece 1680 geçerli kart pozisyonu var, bu yüzden hardcoding 210 bayttan biraz fazla verebilir. (simetri düşünüldüğünde daha az)
lirtosiast

Yanıtlar:


1

Haskell, 580 564 441 bayt

Şu an için ne kadar golf yapabilirim. Diğer dillerin yenebileceğinden emin değilim.

(Definite A) mgibi listelerin listesini arayın [[2,1,0],[2,1,2],[0,0,1]].

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

Test kodu:

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 İadeler:

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

1
Bence düzeltildi. Akşamları iki kez kontrol edip düzgün bir şekilde golf
oynayacak

5

C # - 739663 bayt

Programı tamamlayın, argv'den girdi okur ve çalışıyor gibi görünür. Gibi çalıştır

ThreeMill 1 2 1 1 2 0 0 0 2

Bu giriş yöntemi kabul edilemezse, değiştirmekten memnuniyet duyarım (asla argv kullanmaktan hoşlanmaz).

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))]);}}

Bunu dün yayınlamak istemedim, çünkü çok fazla golf oynayamadım (çok fazla zamanım olmadı ve pratik yapamadım), ama henüz bir yanıt olmadığından, ' Yine de yayınlayacağım, kesinlikle ödül beklemiyorum, göndermeden önce onların içine biraz daha fazla çaba harcayan birine gitmeyi tercih ederim!

Düzenleme: Linq daha iyi kullanmak anlamına gelir ints, tüm bools yerine ve her iki foreach döngüler çöküş başardı, büyük tasarruf veren. hSayaç çalışıyor biraz şaşırdım ... ++ böyle ince bir yardımcı programdır.

Program çok basit, sadece olası her hareket setini araştırıyor (bir dize [] kurulu durumunu depolar). Tüm olası hareketlerimizi (bunun sonucu olan tahtalar) tekrarlar ve rakibimizin başarılı bir şekilde yenebileceğimiz ( G) (yani kazandığımız ve yapmadığı) cevap sayısını sayar . Ayrıca olası yanıtların sayısını da sayar (h). Herhangi birini kazanabilirsek, bu mümkün ve toplamı 1 ekliyoruz, eğer hepsini kazanabilirsek, bu kesin ve toplamı 2 ekliyoruz. Bu nedenle maksimum bazıları mümkün olan en iyi sonucumuzdur ve uygun yüzü döndürmek için "(|))" dizesini dizine ekleriz. Ekstra ")" 'a ihtiyacımız olduğunu unutmayın, çünkü eğer kesin bir şekilde toplam 2 veya 3 olabilir (ilk seferde zaten kazanmış herhangi bir yanıtı yenemeyiz gibi görünüyor, bu yüzden olası kontrol biraz yanıltıcı).

Program, tahtadan bir dize üreterek, yani boşlukla ayrılmış satırlar ve sütunlar ile bir zafer olup olmadığını denetler ve bu dizede oyuncunun karakterinin 3'ünden oluşan bir dize arar (ör. "201 201 021 220 002 111" bizim için kazan)

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 
            ]);

    }
}

İşte benim test senaryom:

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

Hangi çıktılar

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

Güzel. İlk olduğunuz için teşekkürler. :) Tamamsa, özellikli sekmesinde birkaç gün daha tutmak için hafta sonundan sonra ödül vereceğim.
insertusernameburada

@insertusernamehere Bu benim için sorun değil, eğer gerçek bir iş yapmaktan rahatsız olmazsam, bu yarın üzerinde biraz daha iş yapabilirim.
VisualMelon

1
Bu bana şu yorumu hatırlatıyor: " FORTY MINUTES için bir soruya cevap veremedim. Bu kritik! Sadece veritabanı detaylarını gönderin ve SQL cevaplarımı ekleyeceğim. Önlemek için çok işim var ve hiçbir sebep yok önlemek için !! "on Stack Overflow neden çalışmıyor? . :)
insertusernameburada

1

PowerShell 576 550 bayt

Kolayca caydırılmayacağım - C # 631 baytın altına inemezse, bunun yerine farklı bir dil kullanmam gerekecek! Leif Willerts'in cevabından 5 bayt vuracağını umuyorum, çünkü PowerShell'e aşırı düşmeme karar verdim, belki sadece bayt sayımları açısından objektif olarak bakmam gerekiyor ...

Bu bir betik, onu sen yönetiyorsun . .\mill.ps1 "201102021". C # cevabımın bir kopyası, sadece çok az deneyim yaşadığım bir dilde. Bunu golf oynamak için çok fazla çaba göstermedim, çünkü ilk etapta çalışmak çok uzun sürdü ve zaten makul derecede kompakt.

Düzenleme: bu [Math]::Floorçağrıları orada bırakamazdı

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]

Nasıl çalıştığının bir açıklaması varsa ... C # yanıtı sizin için, ancak umarım yorumlar yeterince açıktır. Noktalı virgüller tek satır komutuyla mükemmel şekilde eşleşmeyebilir, henüz nerede gerekli olduklarından emin değilim ve her şeyi bir satıra koyduğumda onları kopyalamamıştım.

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

Test komut dosyası (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"

Çıktıları:

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

1

Python 3, 566 557 bayt

Daha fazla golf oynayabileceğimi veya% 30 bonus kazanıp kazanamayacağımı görmem gerekecek, ancak çok fazla ertelemeden sonra, cevabım burada.

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":|"

Ungolfed:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.