Sadece haç ile Tic Tac Toe


32

Giriş

Herkes tic-tac-toe oyununu herkes bilir, ama bu zorlukta, biraz büküm yapacağız. Sadece haçları kullanacağız . Üst üste üç haç yerleştiren ilk kişi kaybeder. İlginç bir gerçek, birileri kaybetmeden önceki maksimum çarpı miktarının 6'ya eşit olmasıdır :

X X -
X - X
- X X

Bu, 3 x 3'lük bir tahta için maksimum miktarın 6 olduğu anlamına gelir . N = 3 için 6 çıktısına ihtiyacımız var.

N = 4 veya 4 x 4'lük bir tahta için başka bir örnek:

X X - X
X X - X
- - - -
X X - X

Bu en uygun çözümdür, maksimum haç miktarının 9'a eşit olduğunu görebilirsiniz . 12 x 12 anakart için en uygun çözüm:

X - X - X - X X - X X -
X X - X X - - - X X - X
- X - X - X X - - - X X
X - - - X X - X X - X -
- X X - - - X - - - - X
X X - X X - X - X X - -
- - X X - X - X X - X X
X - - - - X - - - X X -
- X - X X - X X - - - X
X X - - - X X - X - X -
X - X X - - - X X - X X
- X X - X X - X - X - X

Bu 74 ile sonuçlanır .

Görev

Görev 0'dan büyük bir tamsayı verilen, basittir, bir satır, sütun boyunca veya çapraz olarak bir çizgiye bitişik üç X olmadan yerleştirilebilecek maksimum çapraz miktarını verir.

Test durumları

N     Output
1     1
2     4
3     6
4     9
5     16
6     20
7     26
8     36
9     42

Daha fazla bilgi https://oeis.org/A181018 adresinde bulunabilir .

kurallar

  • Bu , bu yüzden en az sayıda bayt olan gönderim kazanıyor!
  • Bir işlev veya program sağlayabilirsiniz.

7
Bu yüzden soru, bağlantı verdiğiniz sayfadaki formülleri kullanmaktan kaynaklanıyor ...
nicael

2
Matematik ile ilgili yazı üzerine.
AdmBorkBork,

7
@nicael Görebildiğim kadarıyla OEIS makalesi sadece daha düşük sınırlar içeriyor.
Martin Ender

6
Bunu en hızlı kod mücadelesi olarak görmek harika olurdu.
Luke

4
Codegolf çözümü değil, fakat son birkaç gündür "görsel" bir çözücü ile oynuyordum. Jsfiddle'a buradan erişebilirsiniz: jsfiddle.net/V92Gn/3899 Rastgele mutasyonlarla çözümler bulmaya çalışır. "Doğru" cevabı bulursa durmaz, ancak doğru cevapların çoğuna aşağıdaki cevaplardan daha hızlı ulaşabilir.
styletron

Yanıtlar:


11

Pyth, 57 51 49 bayt

L.T.e+*]Ykbbsef!s.AMs.:R3ssmyBdsm_BdCBcTQsD^U2^Q2

@ PeterTaylor'un CJam çözümü gibi, bu kaba kuvvet, bu yüzden O (n 2 2 n 2 ) zamanda çalışır. Çevrimiçi tercüman n = 4 için bir dakika içinde bitmez.

Dene Burada N <4 için .

Çapraz fonksiyonunu deneyin .

L.T.e+*]Ykbb         y(b): diagonals of b (with some trailing [])
s e                  sum of the last (with most ones) array such that
f                    filter lambda T:
 ! s .AM                none of the 3 element sublists are all ones               
   s .:R3               all 3 element sublists
   s s                  flatten
   myBd                 add the diagonals
   sm_B d               add the vertically flipped array and transpose
   CBcTQ                array shaped into Q by Q square, and its transpose
 sD ^U2 ^Q2             all binary arrays of length Q^2 sorted by sum

13

CJam ( 58 56 bayt)

2q~:Xm*{7Yb#W=}:F,Xm*{ee{~0a@*\+}%zS*F},_Wf%:z&Mf*1fb:e>

Bu inanılmaz derecede yavaş ve çok fazla bellek kullanıyor, ancak bu sizin için .

teşrih

2q~:Xm*        e# Read input into X and find Cartesian product {0,1}^X
{7Yb#W=}:F,    e# Filter with a predicate F which rejects arrays with a 111
Xm*            e# Take the Cartesian product possible_rows^X to get possible grids
{              e# Filter out grids with an anti-diagonal 111 by...
  ee{~0a@*\+}% e#   prepending [0]*i to the ith row
  zS*F         e#   transposing, joining on a non-1, and applying F
},
_Wf%:z         e# Copy the filtered arrays and map a 90 degree rotation
&              e# Intersect. The rotation maps horizontal to vertical and
               e# anti-diagonal to diagonal, so this gets down to valid grids
Mf*            e# Flatten each grid
1fb            e# Count its 1s
:e>            e# Select the maximum

Θ(birX)bir1.83928675...Θ(birX2)Θ(birX4) .


O(Xbir3X)

public class A181018 {
    public static void main(String[] args) {
        for (int i = 1; i < 14; i++) {
            System.out.format("%d:\t%d\n", i, calc(i));
        }
    }

    private static int calc(int n) {
        if (n < 0) throw new IllegalArgumentException("n");
        if (n < 3) return n * n;

        // Dynamic programming approach: given two rows, we can enumerate the possible third row.
        // sc[i + rows.length * j] is the greatest score achievable with a board ending in rows[i], rows[j].
        int[] rows = buildRows(n);
        byte[] sc = new byte[rows.length * rows.length];
        for (int j = 0, k = 0; j < rows.length; j++) {
            int qsc = Integer.bitCount(rows[j]);
            for (int i = 0; i < rows.length; i++) sc[k++] = (byte)(qsc + Integer.bitCount(rows[i]));
        }

        int max = 0;
        for (int h = 2; h < n; h++) {
            byte[] nsc = new byte[rows.length * rows.length];
            for (int i = 0; i < rows.length; i++) {
                int p = rows[i];
                for (int j = 0; j < rows.length; j++) {
                    int q = rows[j];
                    // The rows which follow p,q cannot intersect with a certain mask.
                    int mask = (p & q) | ((p << 2) & (q << 1)) | ((p >> 2) & (q >> 1));
                    for (int k = 0; k < rows.length; k++) {
                        int r = rows[k];
                        if ((r & mask) != 0) continue;

                        int pqrsc = (sc[i + rows.length * j] & 0xff) + Integer.bitCount(r);
                        int off = j + rows.length * k;
                        if (pqrsc > nsc[off]) nsc[off] = (byte)pqrsc;
                        if (pqrsc > max) max = pqrsc;
                    }
                }
            }

            sc = nsc;
        }

        return max;
    }

    private static int[] buildRows(int n) {
        // Array length is a tribonacci number.
        int c = 1;
        for (int a = 0, b = 1, i = 0; i < n; i++) c = a + (a = b) + (b = c);

        int[] rows = new int[c];
        int i = 0, j = 1, val;
        while ((val = rows[i]) < (1 << (n - 1))) {
            if (val > 0) rows[j++] = val * 2;
            if ((val & 3) != 3) rows[j++] = val * 2 + 1;
            i++;
        }

        return rows;
    }
}

Etkili yaklaşım ne işe yarar?
lirtosiast

@ThomasKwa, ah, hala üstel, ancak verimli bir şekilde adlandırmanın haklı olduğunu düşünüyorum çünkü OEIS dizisini 3 terim uzatmamı sağladı.
Peter Taylor,

@ThomasKwa, kesin konuşmak gerekirse, bu kadar O(n a^n)nerede a ~= 5.518.
Peter Taylor

4

C 460 456 410 407 362 351 318 bayt

Bu gerçekten kötü bir cevap. Bu bir inanılmaz yavaş kaba kuvvet yaklaşımı.forDöngüleri birleştirerek biraz daha golf oynamaya çalışıyorum .

#define r return
#define d(x,y)b[x]*b[x+y]*b[x+2*(y)]
n,*b;s(i){for(;i<n*(n-2);++i)if(d(i%(n-2)+i/(n-2)*n,1)+d(i,n)+(i%n<n-2&&d(i,n+1)+d(i+2,n-1)))r 1;r 0;}t(x,c,l,f){if(s(0))r 0;b[x]++;if(x==n*n-1)r c+!s(0);l=t(x+1,c+1);b[x]--;f=t(x+1,c);r l>f?l:f;}main(c,v)char**v;{n=atol(v[1]);b=calloc(n*n,4);printf("%d",t(0,0));}

Test Kılıfları

$ ./a.out 1
1$ ./a.out 2
4$ ./a.out 3
6$ ./a.out 4
9$ ./a.out 5
16$

Ungolfed

n,*b; /* board size, board */

s(i) /* Is the board solved? */
{
    for(;i<n*(n-2);++i) /* Iterate through the board */
            if(b[i%(n-2)+i/(n-2)*n]&&b[i%(n-2)+i/(n-2)*n+1]&&b[i%(n-2)+i/(n-2)*n+2] /* Check for horizontal tic-tac-toe */
                    || b[i] && b[i+n] && b[i+2*n] /* Check for vertical tic-tac-toe */
                    || (i%n<n-2
                            && (b[i] &&b [i+n+1] && b[i+2*n+2] /* Check for diagonal tic-tac-toe */
                                    || b[i+2*n] && b[i+n+1] && b[i+2]))) /* Check for reverse diagonal tic-tac-toe */
                    return 1;
    return 0;
}

t(x,c,l,f) /* Try a move at the given index */
{
    if(s(0)) /* If board is solved, this is not a viable path */
            return 0;
    b[x]++;
    if(x==n*n-1) /* If we've reached the last square, return the count */
            return c+!s(0);

    /* Try it with the cross */
    l=t(x+1,c+1);

    /* And try it without */
    b[x]--;
    f=t(x+1,c);

    /* Return the better result of the two */
    return l>f?l:f;
}

main(c,v)
char**v;
{
    n=atol(v[1]); /* Get the board size */
    b=calloc(n*n,4); /* Allocate a board */
    printf("%d",t(0,0)); /* Print the result */
}

Düzenleme: int değişkenlerini kullanılmayan parametreler olarak bildir; y koordinatını kaldırın, sadece indeksi kullanın; değişkeni global yerine parametre listesine taşımak, iletilen gereksiz parametreleri düzeltmek s(); döngüler için birleştirmek, gereksiz parantezleri kaldırmak; yerine &&ile *, ||ile +; Makro-ify satırda 3 çek


Ne kadar yavaş?
Loovjo

@Loovjo daha hızlı hale getirmek için bilgisayarımda bazı küçük değişiklikler yaptı, n = 5 için 15 ms, n = 6 için 12 sn (giriş +1, zaman * 800)!
edc65

@ edc65 Bu benim deneyimimdi. 5'ten büyük herhangi bir şey performans önemli ölçüde yavaştı. 6'dan büyük girişleri
Cole Cameron

Yorumumu yayınladığımda 7 ile başladım. Göreceğiz
edc65

Birkaç karakter daha ile sıkabilirsiniz #define d(x,y)b[x]*b[x+y]*b[x+y+y]; başlangıcını değiştirerek setmek s(i,m){for(m=n-2;ve tüm örneklerini değiştirilmesi n-2; ve değiştirerek b[x]++etmek b[x++]++ve daha sonra değiştirilmesi x==n*n-1ile x==n*n, x+1birlikte xve xbirlikte x-1.
Peter Taylor,

4

C 263 264 283 309

Düzenle Birkaç bayt thx @Peter Taylor - kaydettiğimden daha az tasarruf etti. Sonra 2 bayt daha fazla bellek ayırmak için kullanılır, şimdi daha büyük boyutta deneyebilirim, ancak çok zaman alıyor.

Not Açıklama eklerken, ızgarayı R dizisinde tutarak bayt harcadığımı öğrendim - böylece bulunan çözümü görebiliyorsunuz ... bu sorun için talep edilmiyor !!
Golf versiyonunda kaldırdım

Aslında n = 1..10 cevabını makul bir sürede bulabilen bir golf C programı.

s,k,n,V[9999],B[9999],i,b;K(l,w,u,t,i){for(t=u&t|u*2&t*4|u/2&t/4,--l; i--;)V[i]&t||(b=B[i]+w,l?b+(n+2)/3*2*l>s&&K(l,b,V[i],u,k):b>s?s=b:0);}main(v){for(scanf("%d",&n);(v=V[i]*2)<1<<n;v%8<6?B[V[k]=v+1,k++]=b+1:0)V[k]=v,b=B[k++]=B[i++];K(n,0,0,0,k);printf("%d",s);}

Benim testim:

7 -> 26 10 sn'de
8 -> 36 18 sn'de
9 -> 42 1162 sn

Daha az golf oynadı ve açıklamaya çalışıyor

#include <stdio.h>

int n, // the grid size
    s, // the result
    k, // the number of valid rows 
    V[9999], // the list of valid rows (0..to k-1) as bitmasks
    B[9999], // the list of 'weight' for each valid rows (number of set bits)
    R[99],  // the grid as an array of indices pointing to bitmask in V
    b,i; // int globals set to 0, to avoid int declaration inside functions

// recursive function to fill the grid
int K(
  int l, // number of rows filled so far == index of row to add
  int w, // number of crosses so far
  int u, // bit mask of the preceding line (V[r[l-1]])
  int t, // bit mask of the preceding preceding line (V[r[l-2]])
  int i) // the loop variables, init to k at each call, will go down to 0
{
  // build a bit mask to check the next line 
  // with the limit of 3 crosses we need to check the 2 preceding rows
  t = u&t | u*2 & t*4 | u/2 & t/4; 
  for (; i--; )// loop on the k possibile values in V
  {
    R[l] = i; // store current row in R
    b = B[i] + w; // new number of crosses if this row is accepted
    if ((V[i] & t) == 0) // check if there are not 3 adjacent crosses
      // then check if the score that we can reach from this point
      // adding the missing rows can eventually be greater
      // than the current max score stored in s
      if (b + (n + 2) / 3 * 2 * (n - l - 1) > s)
        if (l > n-2) // if at last row
          s = b > s ? b : s; // update the max score
        else  // not the last row
          K(l + 1, b, V[i], u, k); // recursive call, try to add another row
  }
}

int main(int j)
{
  scanf("%d", &n);

  // find all valid rows - not having more than 2 adjacent crosses
  // put valid rows in array V
  // for each valid row found, store the cross number in array B
  // the number of valid rows will be in k
  for (; i<1 << n; V[k] = i++, k += !b) // i is global and start at 0
    for (b = B[k] = 0, j = i; j; j /= 2) 
      b = ~(j | -8) ? b : 1, B[k] += j & 1;
  K(0,0,0,0,k); // call recursive function to find the max score
  printf("%d\n", s);
}

Bu aslında Java programımla aynı, ancak ilk önce genişlikten önce derinlik. Benim buildRowsyöntemimi taşıyarak en az bir düzine karakterden tasarruf edebilmeniz gerektiğini düşünüyorum ; belki de for(scanf("%d",&n);(v=2*V[i++])<1<<n;v%8<6&&V[++j]=v+1)v&&V[++j]=v;geçerliyse 20 kadar . (Şu anda bir C derleyicisine erişimim yok).
Peter Taylor,

1
@PeterTaylor bir göz atacağım ... sadece tribonacci kelimesi beni korkutuyor
edc65

Sabit 999kodunuz, bu bölümü yoksaymak isteyeceğiniz anlamına gelir. Her ne kadar belki de zor kodlanmış olmasa da, ilke olarak 11 veya 12'den büyük girdilerle başa çıkabilmeniz için
Peter Taylor

@PeterTaylor Bitleri saymak için C'de bir .bitCount yöntemim olsaydı harika olurdu. Ama o ilk fase ben B'deki bit sayısını hesaplıyorum, sadece V'deki bit maskelerini değil
edc65

2

Ruby, 263 bayt

Bu aynı zamanda kaba bir güç çözümü ve Cole Cameron tarafından C cevabı ile aynı sorunlarla karşı karşıya, ancak bu yakut ve C değil çünkü daha yavaş. Ama hey, daha kısa.

c=->(b){b.transpose.all?{|a|/111/!~a*''}}
m=->(b,j=0){b[j/N][j%N]=1
x,*o=b.map.with_index,0
c[b]&&c[b.transpose]&&c[x.map{|a,i|o*(N-i)+a+o*i}]&&c[x.map{|a,i|o*i+a+o*(N-i)}]?(((j+1)...N*N).map{|i|m[b.map(&:dup),i]}.max||0)+1:0}
N=$*[0].to_i
p m[N.times.map{[0]*N}]

Test durumları

$ ruby A181018.rb 1
1
$ ruby A181018.rb 2
4
$ ruby A181018.rb 3
6
$ ruby A181018.rb 4
9
$ ruby A181018.rb 5
16

Ungolfed

def check_columns(board)
  board.transpose.all? do |column|
    !column.join('').match(/111/)
  end
end

def check_if_unsolved(board)
  check_columns(board) && # check columns
    check_columns(board.transpose) && # check rows
    check_columns(board.map.with_index.map { |row, i| [0] * (N - i) + row + [0] * i }) && # check decending diagonals
    check_columns(board.map.with_index.map { |row, i| [0] * i + row + [0] * (N - i) }) # check ascending diagonals
end

def maximum_crosses_to_place(board, index=0)
  board[index / N][index % N] = 1 # set cross at index
  if check_if_unsolved(board)
    crosses = ((index + 1)...(N*N)).map do |i|
      maximum_crosses_to_place(board.map(&:dup), i)
    end
    maximum_crosses = crosses.max || 0
    maximum_crosses + 1
  else
    0
  end
end

N = ARGV[0].to_i
matrix_of_zeros = N.times.map{ [0]*N }

puts maximum_crosses_to_place(matrix_of_zeros)

1

Haskell, 143 bayt

Bazı açılardan bu yapılmaz, ama ben eğlendim bu yüzden işte:

  • Yatay "kazanma" düzenini kontrol etmek farklı satırlara uygulanırsa geçersiz olur, N <3 girişi 0 döndürür
  • "Diziler", bitlere paketlenmiş tam sayılardır, bu nedenle kolayca numaralandırılabilir
  • ((i! x) y), x değerinin y çarpı bitini verir, negatif endeksler 0 döndürür, böylece aralık sabittir (sınır kontrolü yoktur) ve zincirlendiğinde daha az parantez
  • Sınırlar kontrol edilmediğinden, her biri için 81 * 4 = 324 paterni kontrol eder mümkün maksimum , dizüstü bilgisayarımı 9 saniye süren N = 3'e, N = 5 bitmesi için çok uzun sürüyor.
  • 1/0 üzerindeki Boolean mantığı, T / F için yer kazanmak için kullanılır; örneğin (*) &&, (1-x) (x değil) vb.
  • Diziler yerine tamsayıları kontrol ettiği için, bir desen farklı satırlar arasında kontrol edilmediğinden emin olmak için gerekli (div p1 L) == (div p2 L), burada L satır uzunluğu ve p1, p2 konumdur.
  • Olası maksimum değerin değeri Hamming Ağırlığıdır.

İşte kod:

r=[0..81]
(%)=div
s=sum
i!x|i<0=(*0)|0<1=(*mod(x%(2^i))2)
f l=maximum[s[i!x$1-s[s[1#2,l#(l+l),(l+1)#(l+l+2),(1-l)#(2-l-l)]|p<-r,let  a#b=p!x$(p+a)!x$(p+b)!x$s[1|p%l==(p+mod b l)%l]]|i<-r]|x<-[0..2^l^2]]
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.