Tic-tac-toe chỉ với chéo


32

Giới thiệu

Mọi người đều biết trò chơi tic-tac-toe, nhưng trong thử thách này, chúng tôi sẽ giới thiệu một chút thay đổi. Chúng tôi sẽ chỉ sử dụng chéo . Người đầu tiên đặt ba chữ thập liên tiếp bị mất. Một sự thật thú vị là số lượng vượt qua tối đa trước khi ai đó thua, bằng 6 :

X X -
X - X
- X X

Điều đó có nghĩa là đối với một bảng 3 x 3, số tiền tối đa là 6 . Vì vậy, với N = 3, chúng ta cần xuất 6.

Một ví dụ khác, cho N = 4 hoặc bảng 4 x 4:

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

Đây là một giải pháp tối ưu, bạn có thể thấy rằng số lượng chéo tối đa bằng 9 . Một giải pháp tối ưu cho bảng 12 x 12 là:

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

Kết quả này là 74 .

Nhiệm vụ

Tác vụ rất đơn giản, với một số nguyên lớn hơn 0, xuất ra số lượng chéo tối đa có thể được đặt không có ba chữ X liền kề trong một hàng dọc theo một hàng, cột hoặc theo đường chéo.

Các trường hợp thử nghiệm

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

Thông tin chi tiết có thể được tìm thấy tại https://oeis.org/A181018 .

Quy tắc

  • Đây là , vì vậy bài nộp có số byte ít nhất sẽ thắng!
  • Bạn có thể cung cấp một chức năng hoặc một chương trình.

7
Vì vậy, câu hỏi chỉ cần sử dụng các công thức trong trang bạn đã liên kết ...
nicael


7
@nicael Theo như tôi có thể thấy, bài viết OEIS chỉ chứa giới hạn thấp hơn.
Martin Ender

6
Sẽ thật tuyệt khi xem đây là một thử thách mã nhanh nhất.
Lu-ca

4
Không phải là một giải pháp codegolf, nhưng tôi đã chơi với một người giải "trực quan" trong vài ngày qua. Bạn có thể truy cập jsfiddle tại đây: jsfiddle.net/V92Gn/3899 Nó cố gắng tìm giải pháp thông qua các đột biến ngẫu nhiên. Sẽ không dừng lại nếu tìm thấy câu trả lời "đúng", nhưng nó có thể đi đến nhiều giải pháp chính xác nhanh hơn nhiều so với những câu trả lời dưới đây.
styletron

Câu trả lời:


11

Pyth, 57 51 49 byte

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

Giống như giải pháp CJam của @ PeterTaylor, đây là lực lượng vũ phu, vì vậy nó chạy trong thời gian O (n 2 2 n 2 ). Trình thông dịch trực tuyến không hoàn thành trong vòng một phút với n = 4.

Hãy thử ở đây cho N <4.

Hãy thử chức năng đường chéo .

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 byte)

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

Điều này cực kỳ chậm và sử dụng rất nhiều bộ nhớ, nhưng đó là dành cho bạn.

Mổ xẻ

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

Θ(aX)a1.83928675Θ(aX2)Θ(aX4)


O(Xmột3X)

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

Cách tiếp cận hiệu quả chạy trong?
lirtosiast

@ThomasKwa, ồ, nó vẫn còn theo cấp số nhân, nhưng tôi nghĩ thật hợp lý khi gọi nó là hiệu quả vì nó cho phép tôi mở rộng chuỗi OEIS theo 3 điều khoản.
Peter Taylor

@ThomasKwa, chính xác là, nó O(n a^n)ở đâu a ~= 5.518.
Peter Taylor

4

C, 460 456 410 407 362 351 318 byte

Đây là một câu trả lời thực sự xấu. Đó là một cách tiếp cận vũ phu cực kỳ chậm.Tôi đang cố gắng đánh gôn thêm một chút bằng cách kết hợp các forvòng lặp.

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

Các trường hợp thử nghiệm

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

Ung dung

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 */
}

Chỉnh sửa: Khai báo biến int là tham số không sử dụng; loại bỏ tọa độ y, chỉ cần sử dụng chỉ mục; di chuyển biến vào danh sách tham số thay vì toàn cục, sửa các tham số không cần thiết được chuyển đến s(); kết hợp cho các vòng lặp, loại bỏ các dấu ngoặc đơn không cần thiết; thay thế &&bằng *, ||bằng +; macro-ify kiểm tra 3 liên tiếp


Làm thế nào là chậm?
Loovjo

@Loovjo đã thử trên PC của tôi với một số thay đổi nhỏ để làm cho nó nhanh hơn, 15ms cho n = 5, 12 giây cho n = 6 (đầu vào +1, thời gian * 800)!
edc65

@ edc65 Đó là kinh nghiệm của tôi. Bất cứ điều gì lớn hơn 5 hiệu suất đã chậm đáng kể. Tôi không bận tâm với việc thử đầu vào lớn hơn 6.
Cole Cameron

Tôi bắt đầu với 7 khi tôi đăng bình luận của tôi. Chúng ta sẽ thấy
edc65

Bạn có thể vắt thêm một vài ký tự với #define d(x,y)b[x]*b[x+y]*b[x+y+y]; bằng cách thay đổi khi bắt đầu sđến s(i,m){for(m=n-2;và thay thế tất cả các trường hợp n-2; và bằng cách thay đổi b[x]++thành b[x++]++và sau đó thay thế x==n*n-1bằng x==n*n, x+1bằng xxbằng x-1.
Peter Taylor

4

C 263 264 283 309

Chỉnh sửa Một vài byte được lưu thx @Peter Taylor - ít hơn tôi mong đợi. Sau đó, 2 byte được sử dụng để phân bổ thêm một số bộ nhớ, bây giờ tôi có thể thử kích thước lớn hơn, nhưng nó trở nên rất tốn thời gian.

chú thích Trong khi thêm lời giải thích, tôi phát hiện ra rằng tôi đang lãng phí byte giữ lưới trong mảng R - để bạn có thể thấy giải pháp được tìm thấy ... nó không được yêu cầu cho thử thách này !!
Tôi đã loại bỏ nó trong phiên bản golf

Một chương trình C được đánh gôn thực sự có thể tìm thấy câu trả lời cho n = 1..10 trong thời gian hợp lý.

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

Bài kiểm tra của tôi:

7 -> 26 trong 10 giây
8 -> 36 trong 18 giây
9 -> 42 trong 1162 giây

Ít chơi gôn và cố gắng giải thích

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

Điều này về cơ bản giống như chương trình Java của tôi nhưng trước hết sâu hơn là đầu tiên. Tôi nghĩ bạn sẽ có thể lưu ít nhất một tá ký tự bằng cách chuyển buildRowsphương thức của tôi ; có thể lên tới 20 nếu for(scanf("%d",&n);(v=2*V[i++])<1<<n;v%8<6&&V[++j]=v+1)v&&V[++j]=v;hợp lệ. (Tôi không có quyền truy cập vào trình biên dịch C ngay bây giờ).
Peter Taylor

1
@PeterTaylor tôi sẽ cung cấp cho nó một cái nhìn ... chỉ là từ cống nạp đang làm tôi sợ hãi
edc65

Mã hóa cứng của bạn 999có nghĩa là bạn sẽ muốn bỏ qua phần đó. Mặc dù có lẽ bạn nên thực sự làm cho nó không được mã hóa cứng, để về nguyên tắc bạn có thể giải quyết các đầu vào lớn hơn 11 hoặc 12.
Peter Taylor

@PeterTaylor nó sẽ hoạt động rất tốt nếu tôi có phương thức .bitCount trong C để đếm bit. Nhưng trong lần đầu tiên đó, tôi sẽ tính số bit trong B, không chỉ các mặt nạ bit trong V
edc65

2

Ruby, 263 byte

Đây cũng là một giải pháp vũ phu và đối mặt với những vấn đề tương tự như câu trả lời C của Cole Cameron, nhưng thậm chí còn chậm hơn vì đây là ruby ​​chứ không phải C. Nhưng này, nó ngắn hơn.

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

Các trường hợp thử nghiệm

$ 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

Ung dung

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 byte

Trong một số cách, điều này không được thực hiện, nhưng tôi đã rất vui vì vậy:

  • Vì việc kiểm tra mẫu "chiến thắng" ngang trả về không hợp lệ nếu được áp dụng trên các hàng khác nhau, đầu vào của N <3 trả về 0
  • Các "mảng" là các số nguyên được giải nén thành các bit, vì vậy dễ dàng đếm được
  • ((i! x) y) cung cấp bit thứ i của x lần y, trong đó các chỉ số âm trả về 0 để phạm vi có thể không đổi (không kiểm tra giới hạn) và ít dấu ngoặc hơn khi bị xiềng xích
  • Bởi vì các giới hạn không được kiểm tra, nó kiểm tra 81 * 4 = 324 mẫu cho mọi mức tối đa có thể, dẫn đến N = 3 lấy máy tính xách tay của tôi 9 giây và N = 5 mất quá nhiều thời gian để tôi hoàn thành
  • Logic Boolean trên 1/0 được sử dụng cho T / F để tiết kiệm không gian, ví dụ (*) là &&, (1-x) là (không phải x), v.v.
  • Vì nó kiểm tra số nguyên thay vì mảng, (div p1 L) == (div p2 L) là cần thiết để đảm bảo mẫu không được kiểm tra trên các hàng khác nhau, trong đó L là chiều dài hàng và p1, p2 là vị trí
  • Giá trị tối đa có thể là Trọng lượng Hamming của nó

Đây là mã:

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]]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.