Các nguyên tắc toán học / tính toán đằng sau trò chơi này là gì?


196

Con tôi có trò chơi thú vị này tên là Spot It! Các ràng buộc trò chơi (như tốt nhất tôi có thể mô tả) là:

  • Nó là một bộ gồm 55 thẻ
  • Trên mỗi thẻ có 8 hình ảnh độc đáo (nghĩa là một thẻ không thể có 2 hình ảnh giống nhau)
  • Cho bất kỳ 2 thẻ được chọn từ bộ bài, có 1 và chỉ 1 hình ảnh phù hợp .
  • Các hình ảnh phù hợp có thể được chia tỷ lệ khác nhau trên các thẻ khác nhau nhưng điều đó chỉ để làm cho trò chơi khó hơn (tức là một cây nhỏ vẫn khớp với cây lớn hơn)

Nguyên tắc của trò chơi là: lật 2 lá bài và bất cứ ai lần đầu tiên chọn bức tranh phù hợp đều được điểm.

Đây là một hình ảnh để làm rõ:

phát hiện ra nó

(Ví dụ: bạn có thể nhìn thấy từ 2 thẻ dưới cùng bên trên rằng hình ảnh phù hợp là khủng long xanh. Giữa hình dưới cùng bên phải và giữa bên phải, đó là đầu của chú hề.)

Tôi đang cố gắng để hiểu những điều sau đây:

  1. Số lượng hình ảnh khác nhau tối thiểu cần có để đáp ứng các tiêu chí này là gì và bạn sẽ xác định điều này như thế nào?

  2. Sử dụng mã giả (hoặc Ruby), làm thế nào bạn có thể tạo 55 thẻ trò chơi từ một mảng N hình ảnh (trong đó N là số lượng tối thiểu từ câu hỏi 1)?

Cập nhật:

Hình ảnh xảy ra nhiều hơn hai lần mỗi bộ bài (trái với những gì một số người đã phỏng đoán). Xem hình ảnh của 3 thẻ, mỗi thẻ có một tia sét:3 thẻ


64
+1 để biến một trò chơi thành thứ gì đó làm tổn thương não tôi.
quán rượu

3
Số lượng hình ảnh tối thiểu trên mỗi thẻ, hoặc số lượng hình ảnh tối thiểu cho rằng có 8 hình ảnh trên mỗi thẻ? Ngoài ra, có phải mọi hình ảnh phải phù hợp?
thật

7
Tôi nghĩ bạn cần thêm nhiều ràng buộc hơn. Nếu không, bạn có thể đặt một quả táo vào mỗi thẻ, sau đó thêm bất kỳ số lượng hình ảnh độc đáo nào vào mỗi thẻ. Mỗi cặp thẻ sẽ chỉ phù hợp với hình ảnh của quả táo.
mbeckish

8
@cabaret: Trong trường hợp đó bạn sẽ thích thiết lập . Không thể tin được vui vẻ và làm nặng thêm.
dmckee --- ex-moderator mèo con

4
Trong khi đây là một câu hỏi hay, nó đã được hỏi trên trang web toán học (bởi tôi). Có vẻ hơi lạc đề ở đây. - math.stackexchange.com/questions/36798/iêu
Javid Jamae

Câu trả lời:


148

Hình học hữu hạn chiếu

Các tiên đề của hình học chiếu (mặt phẳng) hơi khác so với hình học Euclide:

  • Mỗi hai điểm có chính xác một dòng đi qua chúng (điều này giống nhau).
  • Mỗi hai dòng gặp nhau ở đúng một điểm (điều này hơi khác so với Euclid).

Bây giờ, thêm "hữu hạn" vào súp và bạn có câu hỏi:

Chúng ta có thể có một hình học chỉ với 2 điểm? Với 3 điểm? Với 4? Với 7?

Vẫn còn những câu hỏi mở về vấn đề này nhưng chúng tôi biết điều này:

  • Nếu có hình học có Qđiểm, thì Q = n^2 + n + 1nđược gọi là orderhình học.
  • n+1điểm trong mỗi dòng.
  • Từ mọi điểm, vượt qua chính xác n+1các dòng.
  • Tổng số dòng cũng được Q.

  • Và cuối cùng, nếu nlà số nguyên tố, thì tồn tại một dạng hình học của trật tự n.


Điều đó có liên quan gì đến câu đố, người ta có thể hỏi.

Đặt cardthay pointpicturethay vì linevà các tiên đề trở thành:

  • Mỗi hai thẻ có chính xác một hình ảnh chung.
  • Đối với mỗi hai hình ảnh có chính xác một thẻ có cả hai.

Bây giờ, hãy lấy n=7và chúng ta có order-7hình học hữu hạn với Q = 7^2 + 7 + 1. Điều đó làm cho Q=57dòng (hình ảnh) và Q=57điểm (thẻ). Tôi đoán các nhà sản xuất câu đố đã quyết định rằng 55 là số tròn nhiều hơn 57 và bỏ lại 2 thẻ.

Chúng tôi cũng nhận được n+1 = 8, vì vậy từ mỗi điểm (thẻ), 8 dòng vượt qua (8 hình ảnh xuất hiện) và mỗi dòng (hình ảnh) có 8 điểm (xuất hiện trong 8 thẻ).


Đây là một đại diện của mặt phẳng chiếu hình hữu hạn (thứ tự-2) nổi tiếng nhất với 7 điểm, được gọi là Mặt phẳng Fano , được sao chép từ Noelle Evans - Trang vấn đề hình học hữu hạn

nhập mô tả hình ảnh ở đây

Tôi đã nghĩ đến việc tạo ra một hình ảnh giải thích làm thế nào mặt phẳng bậc 2 ở trên có thể tạo ra một câu đố tương tự với 7 thẻ và 7 hình ảnh, nhưng sau đó một liên kết từ câu hỏi song sinh math.exchange có sơ đồ chính xác như vậy: Dobble-et- la-geometrie-finie

Máy bay Fano


9
Vì vậy, trò chơi này thể hiện hình học phi Euclide? Nó có đúng không khi nói rằng Thẻ đúng?
RMorrisey

2
Điều này nghe có vẻ tuyệt vời, nhưng tôi không chắc chắn rằng nó thực sự mô hình hóa vấn đề tốt. @ypercube, bạn có thể giải thích thêm một chút lý do tại sao bạn nghĩ rằng sự tương tự giữa thẻ / hình ảnh và điểm / dòng là hợp lệ?
Nate Kohl

@Nate: Sự tương tự thứ 1 every two cards have exactly one picture in common, được nêu trong câu hỏi. Lần thứ 2 for every two pictures there is exactly one card that has both of them, OP có thể cho chúng tôi biết nếu bộ trò chơi thỏa mãn nó.
ypercubeᵀᴹ

4
Câu trả lời tuyệt vời! Một cái nhìn sâu sắc, nhận ra rằng trò chơi phù hợp với các thuộc tính của Máy bay phóng xạ Order-7, cộng với một trong những giải thích tốt nhất về Máy bay phóng xạ cho các giáo dân mà tôi đã thấy.
RBarryYoung

3
Xuất sắc. Tôi sẽ cần đọc thêm 100 lần nữa để cố gắng tìm ra cách tạo bộ thẻ bằng Python ...
Jared

22

Đối với những người gặp khó khăn khi hình dung hình học mặt phẳng chiếu với 57 điểm, có một cách thực sự hay, trực quan để xây dựng trò chơi với 57 thẻ và 57 biểu tượng (dựa trên câu trả lời của Yuval Filmus cho câu hỏi này ):

  1. Đối với thẻ có 8 ký hiệu, tạo lưới 7x7 gồm các ký hiệu duy nhất.
  2. Thêm 8 biểu tượng cho "độ dốc" từ 0 đến 6, cộng với một biểu tượng cho độ dốc vô cực.
  3. Mỗi thẻ là một đường trên lưới (7 ký hiệu) cộng với một ký hiệu từ độ dốc được đặt cho độ dốc của đường. Các dòng có phần bù (tức là điểm bắt đầu ở bên trái) và độ dốc (nghĩa là có bao nhiêu biểu tượng để đi lên cho mỗi bước bên phải). Khi dòng rời khỏi lưới ở trên cùng, nhập lại ở dưới cùng. Xem hình ví dụ này (hình ảnh từ boardgamegeek ) cho hai thẻ như vậy:

Hai thẻ ví dụ (đỏ và xanh lục) được lấy dưới dạng các đường từ lưới

Trong ví dụ này, tôi lấy một dòng có độ dốc bằng không (màu đỏ) và một dòng có độ dốc 1 (màu xanh lá cây). Chúng giao nhau tại đúng một điểm chung (con cú).

Phương pháp này đảm bảo rằng hai thẻ bất kỳ có chính xác một ký hiệu chung, bởi vì

  1. Nếu các độ dốc khác nhau, thì các đường sẽ luôn giao nhau tại đúng một điểm.
  2. Nếu các độ dốc là như nhau, thì các đường sẽ không giao nhau và sẽ không có ký hiệu chung từ lưới. Trong trường hợp này, biểu tượng độ dốc sẽ giống nhau.

Bằng cách này, chúng ta có thể xây dựng các thẻ 7x7 (7 độ lệch và 7 độ dốc).

Chúng tôi cũng có thể xây dựng bảy thẻ bổ sung từ các đường thẳng đứng qua lưới (tức là lấy từng cột). Đối với những người, biểu tượng độ dốc vô cực được sử dụng.

Bởi vì mỗi thẻ bao gồm bảy biểu tượng từ lưới và chính xác một biểu tượng "độ dốc", chúng tôi có thể tạo thêm một thẻ, chỉ đơn giản bao gồm tất cả 8 biểu tượng độ dốc.

Điều này khiến chúng ta có 7x8 + 1 = 57 thẻ có thể và 7 x 7 + 8 = 57 ký hiệu bắt buộc.

(Đương nhiên, điều này chỉ hoạt động với lưới có số nguyên tố (ví dụ n = 7). Mặt khác, các đường có độ dốc khác nhau có thể có 0 hoặc nhiều hơn một giao điểm nếu độ dốc là ước của kích thước lưới.)


18

Vì vậy, có k = 55 thẻ chứa m = 8 ảnh mỗi nhóm từ tổng số n ảnh. Chúng ta có thể xác định lại các câu hỏi 'Có bao nhiêu hình ảnh n sao chúng ta cần, để chúng ta có thể xây dựng một tập các k thẻ chỉ với một hình ảnh chia sẻ giữa bất kỳ cặp thẻ?' tương đương bằng cách hỏi:

Cho một không gian vectơ n chiều và tập hợp tất cả các vectơ chứa chính xác các phần tử m bằng một và tất cả các số 0 khác, có n lớn đến mức nào, để chúng ta có thể tìm thấy một tập hợp các vectơ k , có các sản phẩm chấm cặp tất cả bằng 1 ?

Có chính xác ( n chọn m ) các vectơ có thể để xây dựng các cặp từ đó. Vì vậy, ít nhất chúng ta cần một n đủ lớn để ( n chọn m )> = k . Đây chỉ là một giới hạn thấp hơn, vì vậy để hoàn thành ràng buộc tương thích theo cặp, chúng ta có thể cần n cao hơn nhiều .

Chỉ để thử nghiệm một chút, tôi đã viết một chương trình Haskell nhỏ để tính toán các bộ thẻ hợp lệ:

Chỉnh sửa: Tôi mới nhận ra sau khi xem giải pháp của Neil và Gajet, rằng thuật toán tôi sử dụng không phải lúc nào cũng tìm ra giải pháp tốt nhất có thể, vì vậy mọi thứ dưới đây không nhất thiết phải hợp lệ. Tôi sẽ cố gắng cập nhật mã của tôi sớm.

module Main where

cardCandidates n m = cardCandidates' [] (n-m) m
cardCandidates' buildup  0  0 = [buildup]
cardCandidates' buildup zc oc
    | zc>0 && oc>0 = zerorec ++ onerec
    | zc>0         = zerorec
    | otherwise    = onerec
    where zerorec = cardCandidates' (0:buildup) (zc-1) oc
          onerec  = cardCandidates' (1:buildup) zc (oc-1)

dot x y = sum $ zipWith (*) x y
compatible x y = dot x y == 1

compatibleCards = compatibleCards' []
compatibleCards' valid     [] = valid
compatibleCards' valid (c:cs)
  | all (compatible c) valid = compatibleCards' (c:valid) cs
  |                otherwise = compatibleCards'    valid  cs

legalCardSet n m = compatibleCards $ cardCandidates n m

main = mapM_ print [(n, length $ legalCardSet n m) | n<-[m..]]
  where m = 8

Kết quả số lượng thẻ tương thích tối đa cho m = 8 hình ảnh trên mỗi thẻ cho số lượng hình ảnh khác nhau để chọn từ n cho vài n đầu tiên trông như thế này:

Phương pháp vũ phu này không đi được rất xa mặc dù do vụ nổ tổ hợp. Nhưng tôi nghĩ nó vẫn có thể thú vị.

Thật thú vị, dường như cho m đã , k tăng với n chỉ đến một n nhất định , sau đó nó không đổi.

Điều này có nghĩa là, đối với mỗi số lượng hình ảnh trên mỗi thẻ, có một số lượng hình ảnh nhất định để lựa chọn, dẫn đến số lượng thẻ pháp lý tối đa có thể. Thêm nhiều hình ảnh để chọn từ trước đó, số lượng tối ưu sẽ không làm tăng số lượng thẻ hợp pháp hơn nữa.

Một vài k tối ưu đầu tiên là:

bảng k tối ưu


Đó chỉ là một nỗ lực ban đầu ở một ràng buộc, phải không? Bạn chưa kết hợp yêu cầu "các sản phẩm chấm đôi bằng 1" ...
Nemo

Rõ ràng cú pháp highlighter ở đây không thực sự hỗ trợ Haskell chưa ( meta.stackexchange.com/questions/78363/... ), nhưng tôi sẽ quăng trong gợi ý chỉ trong trường hợp nó trong tương lai.
BoltClock

@BoltClock cảm ơn bạn đã chỉnh sửa! tôi không biết bạn có thể đưa ra gợi ý cho việc tô sáng cú pháp theo ngôn ngữ cụ thể.
Thies Heidecke

Nó chưa được biết đến nhiều lắm :)
BoltClock

9

Những người khác đã mô tả khung chung cho thiết kế (mặt phẳng chiếu hữu hạn) và chỉ ra cách tạo các mặt phẳng chiếu hữu hạn theo thứ tự chính. Tôi chỉ muốn điền vào một số khoảng trống.

Các mặt phẳng chiếu hữu hạn có thể được tạo ra cho nhiều đơn hàng khác nhau, nhưng chúng đơn giản nhất trong trường hợp thứ tự chính p . Sau đó, các số nguyên modulo ptạo thành một trường hữu hạn có thể được sử dụng để mô tả tọa độ cho các điểm và đường thẳng trong mặt phẳng. Có 3 loại khác nhau của tọa độ cho điểm: (1,x,y), (0,1,x), và (0,0,1), nơi xycó thể đảm nhận các giá trị từ 0đến p-1. 3 loại điểm khác nhau giải thích công thức p^2+p+1cho số điểm trong hệ thống. Chúng tôi cũng có thể mô tả dòng với cùng 3 loại khác nhau của tọa độ: [1,x,y], [0,1,x], và [0,0,1].

Chúng tôi tính toán xem một điểm và đường thẳng có phải là sự cố hay không bằng cách sản phẩm chấm của tọa độ của chúng có bằng 0 mod hay không p. Vì vậy, ví dụ điểm (1,2,5)và đường thẳng [0,1,1]là sự cố p=7kể từ khi 1*0+2*1+5*1 = 7 == 0 mod 7, nhưng điểm (1,3,3)và đường thẳng [1,2,6]không phải là sự cố kể từ đó 1*1+3*2+3*6 = 25 != 0 mod 7.

Dịch sang ngôn ngữ của thẻ và hình ảnh, điều đó có nghĩa là thẻ có tọa độ (1,2,5)chứa hình ảnh có tọa độ [0,1,1], nhưng thẻ có tọa độ (1,3,3)không chứa hình ảnh có tọa độ [1,2,6]. Chúng ta có thể sử dụng quy trình này để phát triển một danh sách đầy đủ các thẻ và hình ảnh mà chúng chứa.

Nhân tiện, tôi nghĩ việc hình ảnh như điểm và thẻ là đường thẳng thì dễ dàng hơn, nhưng có sự đối ngẫu trong hình học chiếu giữa điểm và đường nên thực sự không thành vấn đề. Tuy nhiên, trong phần tiếp theo tôi sẽ sử dụng điểm cho hình ảnh và đường kẻ cho thẻ.

Các công trình xây dựng tương tự cho bất kỳ lĩnh vực hữu hạn. Chúng ta biết rằng có một trường hữu hạn của trật tự qnếu và chỉ khi q=p^k, một quyền lực chính. Trường được gọi là GF(p^k)viết tắt của "trường Galois". Các trường không dễ dàng để xây dựng trong trường hợp nguồn chính như trong trường hợp chính.

May mắn thay, công việc khó khăn đã được thực hiện và thực hiện trong phần mềm miễn phí, cụ thể là Sage . Ví dụ, để có được một thiết kế mặt phẳng chiếu của thứ tự 4, chỉ cần gõ

print designs.ProjectiveGeometryDesign(2,1,GF(4,'z'))

và bạn sẽ có được đầu ra giống như

ProjectiveGeometryDesign<points=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20], blocks=[[0, 1, 2, 3, 20], [0,
4, 8, 12, 16], [0, 5, 10, 15, 19], [0, 6, 11, 13, 17], [0, 7, 9, 14,
18], [1, 4, 11, 14, 19], [1, 5, 9, 13, 16], [1, 6, 8, 15, 18], [1, 7,
10, 12, 17], [2, 4, 9, 15, 17], [2, 5, 11, 12, 18], [2, 6, 10, 14, 16],
[2, 7, 8, 13, 19], [3, 4, 10, 13, 18], [3, 5, 8, 14, 17], [3, 6, 9, 12,
19], [3, 7, 11, 15, 16], [4, 5, 6, 7, 20], [8, 9, 10, 11, 20], [12, 13,
14, 15, 20], [16, 17, 18, 19, 20]]>

Tôi diễn giải như trên: có 21 hình được dán nhãn từ 0 đến 20. Mỗi khối (đường trong hình học chiếu) cho tôi biết hình ảnh nào xuất hiện trên thẻ. Ví dụ, thẻ đầu tiên sẽ có hình 0, 1, 2, 3 và 20; thẻ thứ hai sẽ có hình 0, 4, 8, 12 và 16; và như thế.

Hệ thống của đơn hàng 7 có thể được tạo bởi

print designs.ProjectiveGeometryDesign(2,1,GF(7)) 

tạo ra đầu ra

ProjectiveGeometryDesign<points=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56], blocks=[[0, 1, 2, 3, 4, 5, 6,
56], [0, 7, 14, 21, 28, 35, 42, 49], [0, 8, 16, 24, 32, 40, 48, 50], [0,
9, 18, 27, 29, 38, 47, 51], [0, 10, 20, 23, 33, 36, 46, 52], [0, 11, 15,
26, 30, 41, 45, 53], [0, 12, 17, 22, 34, 39, 44, 54], [0, 13, 19, 25,
31, 37, 43, 55], [1, 7, 20, 26, 32, 38, 44, 55], [1, 8, 15, 22, 29, 36,
43, 49], [1, 9, 17, 25, 33, 41, 42, 50], [1, 10, 19, 21, 30, 39, 48,
51], [1, 11, 14, 24, 34, 37, 47, 52], [1, 12, 16, 27, 31, 35, 46, 53],
[1, 13, 18, 23, 28, 40, 45, 54], [2, 7, 19, 24, 29, 41, 46, 54], [2, 8,
14, 27, 33, 39, 45, 55], [2, 9, 16, 23, 30, 37, 44, 49], [2, 10, 18, 26,
34, 35, 43, 50], [2, 11, 20, 22, 31, 40, 42, 51], [2, 12, 15, 25, 28,
38, 48, 52], [2, 13, 17, 21, 32, 36, 47, 53], [3, 7, 18, 22, 33, 37, 48,
53], [3, 8, 20, 25, 30, 35, 47, 54], [3, 9, 15, 21, 34, 40, 46, 55], [3,
10, 17, 24, 31, 38, 45, 49], [3, 11, 19, 27, 28, 36, 44, 50], [3, 12,
14, 23, 32, 41, 43, 51], [3, 13, 16, 26, 29, 39, 42, 52], [4, 7, 17, 27,
30, 40, 43, 52], [4, 8, 19, 23, 34, 38, 42, 53], [4, 9, 14, 26, 31, 36,
48, 54], [4, 10, 16, 22, 28, 41, 47, 55], [4, 11, 18, 25, 32, 39, 46,
49], [4, 12, 20, 21, 29, 37, 45, 50], [4, 13, 15, 24, 33, 35, 44, 51],
[5, 7, 16, 25, 34, 36, 45, 51], [5, 8, 18, 21, 31, 41, 44, 52], [5, 9,
20, 24, 28, 39, 43, 53], [5, 10, 15, 27, 32, 37, 42, 54], [5, 11, 17,
23, 29, 35, 48, 55], [5, 12, 19, 26, 33, 40, 47, 49], [5, 13, 14, 22,
30, 38, 46, 50], [6, 7, 15, 23, 31, 39, 47, 50], [6, 8, 17, 26, 28, 37,
46, 51], [6, 9, 19, 22, 32, 35, 45, 52], [6, 10, 14, 25, 29, 40, 44,
53], [6, 11, 16, 21, 33, 38, 43, 54], [6, 12, 18, 24, 30, 36, 42, 55],
[6, 13, 20, 27, 34, 41, 48, 49], [7, 8, 9, 10, 11, 12, 13, 56], [14, 15,
16, 17, 18, 19, 20, 56], [21, 22, 23, 24, 25, 26, 27, 56], [28, 29, 30,
31, 32, 33, 34, 56], [35, 36, 37, 38, 39, 40, 41, 56], [42, 43, 44, 45,
46, 47, 48, 56], [49, 50, 51, 52, 53, 54, 55, 56]]>

8

Tôi chỉ tìm được cách thực hiện với 57 hoặc 58 bức ảnh nhưng bây giờ tôi bị đau đầu rất nặng, tôi sẽ đăng mã ruby ​​trong 8-10 giờ sau khi tôi ngủ ngon! chỉ là một gợi ý cho giải pháp của tôi, cứ 7 thẻ chia sẻ cùng một dấu và tổng số 56 thẻ có thể được xây dựng bằng giải pháp của tôi.

đây là mã tạo ra tất cả 57 thẻ mà ypercube đang nói đến. nó sử dụng chính xác 57 hình ảnh và xin lỗi anh chàng tôi đã viết mã C ++ thực tế nhưng biết rằng đó vector <something>là một mảng chứa các giá trị loại somethingrất dễ hiểu mã này làm gì. và mã này tạo raP^2+P+1 các thẻ bằng cách sử dụng P^2+P+1mỗi ảnh chứa P+1hình ảnh và chỉ chia sẻ 1 hình ảnh chung cho mỗi giá trị P chính. có nghĩa là chúng ta có thể có 7 thẻ sử dụng 7 ảnh, mỗi ảnh có 3 ảnh (cho p = 2), 13 thẻ sử dụng 13 ảnh (cho p = 3), 31 thẻ sử dụng 31 ảnh (cho p = 5), 57 thẻ cho 57 ảnh (với p = 7) và cứ thế ...

#include <iostream>
#include <vector>

using namespace std;

vector <vector<int> > cards;

void createcards(int p)
{
    cards.resize(0);
    for (int i=0;i<p;i++)
    {
        cards.resize(cards.size()+1);
        for(int j=0;j<p;j++)
        {
            cards.back().push_back(i*p+j);
        }
        cards.back().push_back(p*p+1);
    }

    for (int i=0;i<p;i++)
    {
        for(int j=0;j<p;j++)
        {
            cards.resize(cards.size()+1);
            for(int k=0;k<p;k++)
            {
                cards.back().push_back(k*p+(j+i*k)%p);
            }
            cards.back().push_back(p*p+2+i);
        }
    }

    cards.resize(cards.size()+1);

    for (int i=0;i<p+1;i++)
        cards.back().push_back(p*p+1+i);
}

void checkCards()
{
    cout << "---------------------\n";
    for(unsigned i=0;i<cards.size();i++)
    {
        for(unsigned j=0;j<cards[i].size();j++)
        {
            printf("%3d",cards[i][j]);
        }
        cout << "\n";
    }
    cout << "---------------------\n";
    for(unsigned i=0;i<cards.size();i++)
    {
        for(unsigned j=i+1;j<cards.size();j++)
        {
            int sim = 0;
            for(unsigned k=0;k<cards[i].size();k++)
                for(unsigned l=0;l<cards[j].size();l++)
                    if (cards[i][k] == cards[j][l])
                        sim ++;
            if (sim != 1)
                cout << "there is a problem between cards : " << i << " " << j << "\n";

        }
    }
}

int main()
{
    int p;
    for(cin >> p; p!=0;cin>> p)
    {
        createcards(p);
        checkCards();
    }
}

một lần nữa xin lỗi vì mã bị trì hoãn.


37
Tôi có một bằng chứng thanh lịch về điều này, nhưng than ôi hộp bình luận này quá nhỏ để chứa nó.
đăng

@Gajet: Bạn đã chạy nó cho p=4? (và 21 thẻ / hình ảnh)
ypercubeᵀᴹ

4 không hoạt động trong thuật toán của tôi vì 4 không phải là số nguyên tố, trong thuật toán của tôi, điều quan trọng là p phải là số nguyên tố.
Ali1S 232

@ypercube sau khi kiểm tra lại, có một số lỗi nhỏ trong thuật toán của tôi nhưng tôi đã kiểm tra nó, 2, 3,5,7 và tôi có thể chứng minh cho bất kỳ số nguyên tố nào khác nó sẽ hoạt động, vì vậy đây là mã hoàn chỉnh của tôi (nhưng trong c ++)
Ali1S 232

1
@Gajet: giải pháp tuyệt vời! Bây giờ tôi hiểu tại sao thuật toán tham lam của tôi không luôn tạo ra giải pháp tốt nhất.
Thies Heidecke

6

Đây là giải pháp của Gajet trong Python, vì tôi thấy Python dễ đọc hơn. Tôi đã sửa đổi nó để nó hoạt động với các số không chính. Tôi đã sử dụng Thies insight để tạo một số mã hiển thị dễ hiểu hơn.

from __future__ import print_function
from itertools import *

def create_cards(p):
    for min_factor in range(2, 1 + int(p ** 0.5)):
        if p % min_factor == 0:
            break
    else:
        min_factor = p
    cards = []
    for i in range(p):
        cards.append(set([i * p + j for j in range(p)] + [p * p]))
    for i in range(min_factor):
        for j in range(p):
            cards.append(set([k * p + (j + i * k) % p
                              for k in range(p)] + [p * p + 1 + i]))

    cards.append(set([p * p + i for i in range(min_factor + 1)]))
    return cards, p * p + p + 1

def display_using_stars(cards, num_pictures):
    for pictures_for_card in cards:
        print("".join('*' if picture in pictures_for_card else ' '
                      for picture in range(num_pictures)))

def check_cards(cards):
    for card, other_card in combinations(cards, 2):
        if len(card & other_card) != 1:
            print("Cards", sorted(card), "and", sorted(other_card),
                  "have intersection", sorted(card & other_card))

cards, num_pictures = create_cards(7)
display_using_stars(cards, num_pictures)
check_cards(cards)

Với đầu ra:

***      *   
   ***   *   
      ****   
*  *  *   *  
 *  *  *  *  
  *  *  * *  
*   *   *  * 
 *   **    * 
  **   *   * 
*    * *    *
 * *    *   *
  * * *     *
         ****

2
Tôi nghĩ rằng ba thẻ cuối cùng trong ví dụ của bạn không hợp lệ, vì chúng không chia sẻ hình ảnh với thẻ thứ năm. Chỉ cần kiểm tra mã của tôi trong hơn một giờ trước khi tôi nhận ra nó :) Thật thú vị, có vẻ như kích thước tối đa của một bộ thẻ hợp pháp là 5 cho 4 hình ảnh trên mỗi thẻ và không tăng ngay cả khi có nhiều hình ảnh để lựa chọn.
Thies Heidecke

1
@Thies với sơ đồ tôi tạo bằng mã của Gajet, sẽ dễ hiểu hơn tại sao có (p) + (p * p) + (1)cấu hình chính xác .
Neil G

1
@Neil: Cảm ơn vì sơ đồ được cập nhật, giúp dễ dàng hơn để xem giải pháp của Gajet hoạt động như thế nào!
Thies Heidecke

1
@Gajet: Tôi nghĩ bạn đã sai về all p except 4 and 6. Nếu bạn muốn tạo ra một mặt phẳng hữu hạn, nơi có p*p+p+1các điểm và đường thẳng (thẻ và hình ảnh), thì nó có liên quan finite fieldsvà không rings. Có các trường hữu hạn của trật tự pkhi p là primehoặc a prime power. Mã của bạn hoạt động chính xác cho các số nguyên tố vì các biểu thức như k * p + (j + i * k) % pthể hiện k*p + j + i*kdưới dạng phép nhân và phép cộng trong trường hữu hạn của thứ tự p.
ypercubeᵀᴹ

1
Nó sẽ làm việc một cách chính xác cho quyền hạn thủ quá, nếu bạn có thể thể hiện các hoạt động này (. Mult, bổ sung) trong các lĩnh vực hữu hạn về trật tự p^2, p^3vv Vì vậy, nó sẽ làm việc cho4, 8, 9, 16, 25, 27, ...
ypercubeᵀᴹ

4

Sử dụng z3 định lý prover

Gọi Plà số ký hiệu trên mỗi thẻ. Theo bài viết nàyypercubeᵀᴹcâu trả lời N = P**2 - P + 1tương ứng, có thẻ và ký hiệu. Một cỗ bài có thể được biểu diễn bằng ma trận tỷ lệ có một hàng cho mỗi thẻ và một cột cho mỗi ký hiệu có thể. (i,j)Yếu tố của nó là 1nếu thẻ icó ký hiệuj trên đó. Chúng ta chỉ cần điền vào ma trận này với những ràng buộc sau:

  • mọi phần tử đều bằng 0 hoặc một
  • tổng của mỗi hàng là chính xác P
  • tổng của mỗi cột là chính xác P
  • bất kỳ hai hàng nào cũng phải có chính xác một ký hiệu

Điều đó có nghĩa là N**2các biến và N**2 + 2*N + (N choose 2)ràng buộc. Nó dường như có thể quản lý được trong một thời gian không dài vớiz3 các đầu vào nhỏ.

chỉnh sửa : Thật không may, P = 8 dường như quá lớn đối với phương pháp này. Tôi đã giết quá trình sau 14 giờ tính toán.

from z3 import *
from itertools import combinations

def is_prime_exponent(K):
    return K > 1 and K not in 6  # next non-prime exponent is 10, 
                                 # but that is too big anyway

def transposed(rows):
    return zip(*rows)

def spotit_z3(symbols_per_card):
    K = symbols_per_card - 1
    N = symbols_per_card ** 2 - symbols_per_card + 1
    if not is_prime_exponent(K):
        raise TypeError("Symbols per card must be a prime exponent plus one.")

    constraints = []

    # the rows of the incidence matrix
    s = N.bit_length()
    rows = [[BitVec("r%dc%d" % (r, c), s) for c in range(N)] for r in range(N)]

    # every element must be either 1 or 0
    constraints += [Or([elem == 1, elem == 0]) for row in rows for elem in row]

    # sum of rows and cols must be exactly symbols_per_card
    constraints += [Sum(row) == symbols_per_card for row in rows]
    constraints += [Sum(col) == symbols_per_card for col in transposed(rows)]

    # Any two rows must have exactly one symbol in common, in other words they
    # differ in (symbols_per_card - 1) symbols, so their element-wise XOR will
    # have 2 * (symbols_per_card - 1) ones.
    D = 2 * (symbols_per_card - 1)
    for row_a, row_b in combinations(rows, 2):
        constraints += [Sum([a ^ b for a, b in zip(row_a, row_b)]) == D]

    solver = Solver()
    solver.add(constraints)

    if solver.check() == unsat:
        raise RuntimeError("Could not solve it :(")

    # create the incidence matrix
    model = solver.model()
    return [[model[elem].as_long() for elem in row] for row in rows]


if __name__ == "__main__":
    import sys
    symbols_per_card = int(sys.argv[1])
    incidence_matrix = spotit_z3(symbols_per_card)
    for row in incidence_matrix:
        print(row)

Các kết quả

$python spotit_z3.py 3
[0, 0, 1, 1, 0, 1, 0]
[0, 0, 0, 0, 1, 1, 1]
[0, 1, 0, 1, 0, 0, 1]
[1, 1, 0, 0, 0, 1, 0]
[0, 1, 1, 0, 1, 0, 0]
[1, 0, 0, 1, 1, 0, 0]
[1, 0, 1, 0, 0, 0, 1]
python spotit_z3.py 3  1.12s user 0.06s system 96% cpu 1.225 total

$ time python3 spotit_z3.py 4
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]
[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0]        
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1]
[0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1]
[0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]
[1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0]
[1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
python spotit_z3.py 4  664.62s user 0.15s system 99% cpu 11:04.88 total

$ time python3 spotit_z3.py 5
[1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1]
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1]
[1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0]
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
[1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0]
python spotit_z3.py 5  1162.72s user 20.34s system 99% cpu 19:43.39 total

$ time python3 spotit_z3.py 8
<I killed it after 14 hours of run time.>

4

Tôi rất thích chủ đề này. Tôi xây dựng dự án python github này với các phần của mã này ở đây để vẽ thẻ tùy chỉnh dưới dạng png (để người ta có thể đặt hàng các trò chơi thẻ tùy chỉnh trên internet).

https://github.com/plagtag/ProjectiveGeometry-Game


3

Tôi đã viết một bài viết về cách tạo ra loại sàn này, với mã trong Perl. Mã này không được tối ưu hóa nhưng ít nhất nó có khả năng tạo ra các đơn đặt hàng "hợp lý" ... và một số thứ nữa.

Đây là một ví dụ với thứ tự 8, phải xem xét một phép toán cơ bản phức tạp hơn một chút, bởi vì 8 không phải là số nguyên tố mặc dù một thứ tự hợp lệ để tạo ra các loại sàn này. Xem ở trên hoặc bài viết để được giải thích chi tiết hơn, bên dưới nếu bạn chỉ muốn tạo một Spot-It khó hơn một chút :-)

$ time pg2 8
elements in field: 8
  0. (1, 9, 17, 25, 33, 41, 49, 57, 65)
  1. (0, 9, 10, 11, 12, 13, 14, 15, 16)
  2. (2, 9, 18, 27, 36, 45, 54, 63, 72)
  3. (6, 9, 22, 26, 37, 43, 56, 60, 71)
  4. (7, 9, 23, 32, 34, 46, 52, 59, 69)
  5. (8, 9, 24, 30, 35, 42, 55, 61, 68)
  6. (3, 9, 19, 29, 39, 44, 50, 64, 70)
  7. (4, 9, 20, 31, 38, 48, 53, 58, 67)
  8. (5, 9, 21, 28, 40, 47, 51, 62, 66)
  9. (0, 1, 2, 3, 4, 5, 6, 7, 8)
 10. (1, 10, 18, 26, 34, 42, 50, 58, 66)
 11. (1, 14, 22, 30, 38, 46, 54, 62, 70)
 12. (1, 15, 23, 31, 39, 47, 55, 63, 71)
 13. (1, 16, 24, 32, 40, 48, 56, 64, 72)
 14. (1, 11, 19, 27, 35, 43, 51, 59, 67)
 15. (1, 12, 20, 28, 36, 44, 52, 60, 68)
 16. (1, 13, 21, 29, 37, 45, 53, 61, 69)
 17. (0, 17, 18, 19, 20, 21, 22, 23, 24)
 18. (2, 10, 17, 28, 35, 46, 53, 64, 71)
 19. (6, 14, 17, 29, 34, 48, 51, 63, 68)
 20. (7, 15, 17, 26, 40, 44, 54, 61, 67)
 21. (8, 16, 17, 27, 38, 47, 50, 60, 69)
 22. (3, 11, 17, 31, 37, 42, 52, 62, 72)
 23. (4, 12, 17, 30, 39, 45, 56, 59, 66)
 24. (5, 13, 17, 32, 36, 43, 55, 58, 70)
 25. (0, 49, 50, 51, 52, 53, 54, 55, 56)
 26. (3, 10, 20, 30, 40, 43, 49, 63, 69)
 27. (2, 14, 21, 32, 39, 42, 49, 60, 67)
 28. (8, 15, 18, 28, 37, 48, 49, 59, 70)
 29. (6, 16, 19, 31, 36, 46, 49, 61, 66)
 30. (5, 11, 23, 26, 38, 45, 49, 64, 68)
 31. (7, 12, 22, 29, 35, 47, 49, 58, 72)
 32. (4, 13, 24, 27, 34, 44, 49, 62, 71)
 33. (0, 57, 58, 59, 60, 61, 62, 63, 64)
 34. (4, 10, 19, 32, 37, 47, 54, 57, 68)
 35. (5, 14, 18, 31, 35, 44, 56, 57, 69)
 36. (2, 15, 24, 29, 38, 43, 52, 57, 66)
 37. (3, 16, 22, 28, 34, 45, 55, 57, 67)
 38. (7, 11, 21, 30, 36, 48, 50, 57, 71)
 39. (6, 12, 23, 27, 40, 42, 53, 57, 70)
 40. (8, 13, 20, 26, 39, 46, 51, 57, 72)
 41. (0, 65, 66, 67, 68, 69, 70, 71, 72)
 42. (5, 10, 22, 27, 39, 48, 52, 61, 65)
 43. (3, 14, 24, 26, 36, 47, 53, 59, 65)
 44. (6, 15, 20, 32, 35, 45, 50, 62, 65)
 45. (2, 16, 23, 30, 37, 44, 51, 58, 65)
 46. (4, 11, 18, 29, 40, 46, 55, 60, 65)
 47. (8, 12, 21, 31, 34, 43, 54, 64, 65)
 48. (7, 13, 19, 28, 38, 42, 56, 63, 65)
 49. (0, 25, 26, 27, 28, 29, 30, 31, 32)
 50. (6, 10, 21, 25, 38, 44, 55, 59, 72)
 51. (8, 14, 19, 25, 40, 45, 52, 58, 71)
 52. (4, 15, 22, 25, 36, 42, 51, 64, 69)
 53. (7, 16, 18, 25, 39, 43, 53, 62, 68)
 54. (2, 11, 20, 25, 34, 47, 56, 61, 70)
 55. (5, 12, 24, 25, 37, 46, 50, 63, 67)
 56. (3, 13, 23, 25, 35, 48, 54, 60, 66)
 57. (0, 33, 34, 35, 36, 37, 38, 39, 40)
 58. (7, 10, 24, 31, 33, 45, 51, 60, 70)
 59. (4, 14, 23, 28, 33, 43, 50, 61, 72)
 60. (3, 15, 21, 27, 33, 46, 56, 58, 68)
 61. (5, 16, 20, 29, 33, 42, 54, 59, 71)
 62. (8, 11, 22, 32, 33, 44, 53, 63, 66)
 63. (2, 12, 19, 26, 33, 48, 55, 62, 69)
 64. (6, 13, 18, 30, 33, 47, 52, 64, 67)
 65. (0, 41, 42, 43, 44, 45, 46, 47, 48)
 66. (8, 10, 23, 29, 36, 41, 56, 62, 67)
 67. (7, 14, 20, 27, 37, 41, 55, 64, 66)
 68. (5, 15, 19, 30, 34, 41, 53, 60, 72)
 69. (4, 16, 21, 26, 35, 41, 52, 63, 70)
 70. (6, 11, 24, 28, 39, 41, 54, 58, 69)
 71. (3, 12, 18, 32, 38, 41, 51, 61, 71)
 72. (2, 13, 22, 31, 40, 41, 50, 59, 68)
errors in check: 0

real    0m0.303s
user    0m0.200s
sys 0m0.016s

Mỗi định danh từ 0đến 72có thể được đọc cả dưới dạng định danh thẻ và dưới dạng định danh hình ảnh. Ví dụ: hàng cuối cùng có nghĩa là:

  • thẻ 72chứa hình ảnh 2, 13, 22, ..., 59, 68, VÀ
  • hình ảnh 72xuất hiện trong thẻ 2, 13, 22, ..., 59, và 68.
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.