สร้างตัวตรวจสอบการชนะ win to tic tac toe


13

สร้างโปรแกรมที่สั้นที่สุดในการตรวจสอบที่ได้รับรางวัลใน n dเกม Tic Tac เท้า

โปรแกรมของคุณควรทำงานเมื่อn(ความกว้าง) และd(หมายเลขมิติ) อยู่ในช่วงเหล่านี้:

n∈[3,6]∩ℕ  ie a number from this list: 3,4,5,6
d∈[2,5]∩ℕ  ie a number from this list: 2,3,4,5

n = 3; d = 2(3 2คือ 3 จาก 3):

[][][]
[][][]
[][][]

n = 3; d = 3(3 3เช่น 3 โดย 3 โดย 3):

[][][]
[][][]
[][][]

[][][]
[][][]
[][][]

[][][]
[][][]
[][][]

n = 6; d = 2(6 2คือ 6 จาก 6):

[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]
[][][][][][]

และอื่น ๆ

การชนะ (หากคุณเล่น Tic Tac Toe หลายมิติมากพอจะเป็นเช่นนี้)

เพื่อให้มีการชนะผู้เล่นคนหนึ่งจะต้องมีสี่เหลี่ยมที่อยู่ติดกันทั้งหมดตามแนว นั่นคือผู้เล่นนั้นจะต้องมีการnเคลื่อนไหวในบรรทัดที่จะเป็นผู้ชนะ

ตั้งอยู่ใกล้เคียง:

  • กระเบื้องแต่ละจุด เช่น (0,0,0,0,0) เป็นจุดd=5
  • ไพ่ที่อยู่ติดกันคือไพ่ทั้งคู่ซึ่งอยู่ในหน่วยเดียวกัน d-cube กล่าวอีกนัยหนึ่งระยะทาง Chebyshevระหว่างแผ่นคือ 1
  • กล่าวอีกนัยหนึ่งถ้าจุดpอยู่ติดกับจุดqจากนั้นทุกพิกัดในพิกัดpที่สอดคล้องกันในqความแตกต่างจากมันไม่เกินหนึ่ง นอกจากนี้อย่างน้อยในการประสานงานคู่แตกต่างกันโดยหนึ่ง

บรรทัด:

  • เส้นถูกกำหนดโดยเวกเตอร์และกระเบื้อง เส้นคือแต่ละไทล์ที่กระทบกับสมการ:p0 + t<some vector with the same number of coordinates as p0>

อินพุต :

อินพุตจะเป็น STDIN บรรทัดแรกของการป้อนข้อมูลจะเป็นตัวเลขสองnและในรูปแบบdn,d

หลังจากนี้จะเป็นบรรทัดที่ประกอบด้วยพิกัดที่ระบุการเคลื่อนไหวที่ได้ทำไปแล้ว พิกัดจะแสดงรายการในแบบฟอร์ม: 1,1;2,2;3,3. มุมซ้ายบนเป็นจุดกำเนิด (0,0 สำหรับ 2D) ในกรณีทั่วไปรายการนี้จะเป็นเช่น1,2,...,1,4;4,0,...,6,0;...ที่หมายเลขแรกหมายถึงซ้ายขวา, ที่สองขึ้นลง, ที่สามผ่านมิติที่ 3 ฯลฯ โปรดทราบว่าพิกัดแรกคือตาXแรกที่สอง เป็นOเทิร์นแรก, ....

การป้อนข้อมูลจะถูกตามด้วยการขึ้นบรรทัดใหม่

ผลผลิต :

เอาต์พุตจะเป็น STDOUT เพียงระบุผู้ที่ชนะถ้ามีคนชนะหรือถ้ามันเสมอกัน ถ้ามันไม่ใช่เน็คไทหรือชนะอย่าเอาท์พุทอะไรเลย

นอกจากนี้ระบุว่ามีการปะทะกันของการย้ายนั่นคือถ้ามีการเคลื่อนไหวอย่างน้อยสองครั้งในตำแหน่งเดียวกัน

หากมีการชนะ / เสมอก่อนที่อินพุตจะสิ้นสุดลงโปรแกรมของคุณสามารถทำอะไรก็ได้ที่ต้องการ

กรณีทดสอบ (ทุกคนต้องการแนะนำอีกหรือไม่):

การป้อนข้อมูล:

4,3
0,0,0;1,1,1;1,0,1;2,0,2;0,0,1;2,0,0;2,0,1;3,0,2;3,0,1

ตัวอย่างผลลัพธ์:

X wins

เอาต์พุตอื่นที่เป็นไปได้ (ต้องมีคำอธิบาย):

1

คุณจะกำหนดโทโพโลยีของมิติ n> 3 เพื่อกำหนดว่าเส้นตรงตามแนวทแยงมุมเป็นอย่างไร ตัวอย่างเช่นเส้นใด ๆ ที่ผ่านจุดยอด 3 จุดใด ๆ ที่อยู่ติดกันถือเป็นการชนะบนกระดาน3⁵หรือไม่? สี่เหลี่ยมกลางของเครื่องบิน3²แต่ละอันเชื่อมต่อกับทุกจุดของระนาบอื่นที่มีขอบอยู่บน n-cube หรือไม่?
Comintern

1
@Comintern เป็นไงบ้าง (ฉันอาจอธิบายรายละเอียดแล้ว
Justin

หมายเหตุ: คำจำกัดความที่คุณระบุสำหรับกระเบื้องที่อยู่ติดกันนั้นไม่เทียบเท่ากัน (นั่นคือไม่ใช่ระยะทางแมนฮัตตันเท่ากับหนึ่ง)
โฮเวิร์ด

ยิ่งไปกว่านั้นคุณควรกำหนดว่ามันต้องใช้เวลาในการnเคลื่อนที่เพื่อเป็นผู้ชนะ (ขออภัยที่ไม่ได้โพสต์คำพูดเหล่านี้ไว้ในกล่องทราย แต่ฉันไม่มีเวลาแม้แต่จะเห็นมันที่นั่นเพราะมันถูกโพสต์ในไม่ช้าหลังจาก sandboxing)
โฮเวิร์ด

1
ฉันรู้สึกว่าควรจะมีวิธีแก้ปัญหาสั้น ๆ ใน Prolog ...
Nate Eldredge

คำตอบ:


3

Python, 745 578 ตัวละคร

import sys
x=[]
o=[]
t=1
b=","
k=map
def m(c):
 m=x if t else o
 c=k(int,c.split(b))
 if c in o+x:
  print b
  sys.exit()
 m.append(c)
 r=0
 for p in m:
  r=w(p,m)
 return r
def w(p,m):
 for q in m:
  d=max(k(lambda x,y:abs(x-y),p,q))
  if d==u:
   if e(p,q,m):
    return 1
 return 0
def e(p,q,m):
 v=k(lambda p,q:(p-q)/u,q,p)
 l=p
 for i in range(1,n):
  y=k(lambda j,h:j+h,l,v)
  if y not in m:
   return 0
  l=y
 if not l==q:
  return 0
 return 1
q=sys.stdin.readline
d=q()
v=q()
z=d.split(b)
(n,d)=k(int,z)
a=v.split(";")
u=n-1
for c in a:
 r=m(c)
 if r:
  print t
 t=not t

ฉันทำการเปลี่ยนแปลงบางอย่างและลดขนาดลงเล็กน้อย โปรดทราบว่าการคืนค่า True หมายความว่า x ได้รับรางวัลแล้ว False หมายถึง y won และหมายถึงการย้ายที่ไม่ถูกต้อง


บางสิ่งบางอย่างเปลี่ยนแปลงไปimport * import*ใช้1สำหรับจริงและ0เท็จ (ลบTและF) return -1สามารถreturn-1(ตรวจสอบการลบช่องว่าง) เปลี่ยนชื่อวิธีการของคุณเป็นวิธีการถ่านเดียว ดูเคล็ดลับสำหรับการเพิ่มประสิทธิภาพเพิ่มเติม
Justin

โอ้ขอบคุณฉันไม่ทราบว่าคุณสามารถทำสิ่งเหล่านั้น (กล่าวคือลบช่องว่างระหว่างผลตอบแทนและ -1)
foota

ฉันเล่นกอล์ฟสักเล็กน้อยบนรหัสของคุณ (ซึ่งอาจไม่ถูกต้องทั้งหมด) ผลที่ได้คือที่นี่: ideone.com/Ld2jAH โปรดทำตามคำตอบของคุณอีกครั้งและย่อรหัสให้มากที่สุด เคล็ดลับคำถามสำหรับหลามเป็นประโยชน์อย่างมาก
จัสติน

@foota คุณสามารถทำแทนif l<>q: if not l==q:
mbomb007

3

ไม่ใช่คำตอบ - Java

ฉันอยากรู้อยากเห็นว่ามีวิธีที่แตกต่างกันในการชนะสำหรับ n ที่กำหนดดังนั้นฉันจึงเขียนโค้ดนี้เพื่อแสดงรายการทั้งหมด

import java.util.*;

public class MultiDTTT {
    static Set<Win> wins = new HashSet<Win>();
    static final int d = 3;
    static final int n = 3;
    static final char maxChar = (char)(n-1) + '0'; 

    public static void main(String[] args) throws Exception {
        String pad = "";
        for(int i=0; i<d; i++) pad = pad + "0";
        for(int i=0; i<Math.pow(n,d); i++) {
            String s = Integer.toString(i,n);
            s = pad.substring(s.length()) + s;
            buildWin(s,"",0);
        } 
        System.out.println(wins.size());
        for(Win w : wins) System.out.println(w.toString());
    }

    static void buildWin(String s, String p,int i) {
        if(i<d) {
            if(s.charAt(i) == '0') {
                buildWin(s,p+"u",i+1);
                buildWin(s,p+"s",i+1);
            }
            else if(s.charAt(i) == maxChar) {
                buildWin(s,p+"d",i+1);
                buildWin(s,p+"s",i+1);
            }
            else {
                buildWin(s,p+"s",i+1);
            }
        }
        else {
            if(p.contains("u") || p.contains("d")) wins.add(new Win(s,p));
        }
    }

    static class Win {
        String start;
        String pattern;
        Set<String> list = new HashSet<String>();

        Win(String s, String p) {
            start = s;
            pattern = p;
            char[] sc = s.toCharArray();
            for(int i=0; i<n; i++) {
                list.add(new String(sc));
                for(int j=0; j<d; j++) {
                    switch (p.charAt(j)) {
                        case 'u':
                            sc[j]++;
                            break;
                        case 'd':
                            sc[j]--;
                            break;
                        case 's':
                            break;
                    }
                }
            }
        }

        public String toString() {
            String s = ""; //start + ", " + pattern + "\n    ";
            for(String ss : list) s = s + ss + " ";
            return s;
        }

        public boolean equals(Object x) {
            return (x instanceof Win) && this.list.equals(((Win)x).list);
        }
        public int hashCode(){
            return list.hashCode();
        }
    }
}

ฉันทดสอบด้วยตนเองใน n, d = 2..3,2..3 และดูเหมือนว่าจะทำงาน ... หลังจากนั้นจำนวนวิธีที่เป็นไปได้ที่จะชนะจะเติบโตอย่างรวดเร็วดังแสดงด้านล่าง:

n       1       2       3       4       5       6
d                           
1       1       1       1       1       1       1
2       1       6       8       10      12      14
3       1       28      49      76      109     148
4       1       120     272     520     888     1400
5       1       496     1441    3376    6841    12496
6       1       2016    7448    21280   51012   107744

เมื่อสร้างชุดที่มีชัยชนะทั้งหมดฉันสามารถขยายโปรแกรมเพื่อตรวจสอบอินพุตที่กำหนดกับชุดที่ชนะ แต่แน่นอนว่าวิธีการนั้นจะไม่ชนะกอล์ฟ ดังนั้นฉันจึงพอใจที่จะหยุดอยู่ที่นี่ - ยกเว้นดูเหมือนว่าฉันจะหาวิธีแก้ปัญหาแบบปิดสำหรับจำนวนวิธีที่จะชนะในรูปแบบของ n และ d …มันเป็นจำนวนวิธีที่จะชนะ = 0.5 ((n + 2) ^ d - n ^ d)


2

C ++ 794 849ตัวอักษร

#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
#define _ return
#define Y int
#define Z(a) cout<<#a
#define W(a,b,c) for(a=c;a++<b;)
using namespace std;Y n,d,A[5],P[6],T=1,x[7776]={},i,j,k,a,z,p=pow(n,d);char c;bool B;string s;Y K(){a=P[j];W(k,i,0)a/=n;_ a%n;}Y M(){j=0;z=K();W(j,n,1){if(K()!=z){_ 1;}}_ 0;}Y N(){W(j,n,0)if(K()!=n-1-j)_ 1;_ 0;}Y O(){W(j,n,0)if(K()!=j)_ 1;_ 0;}Y S(){z=0;W(i,d,0){z*=n;z+=A[i];}_ z;}Y C(){a=z=0;W(i,p,0){if(s[i]-'0'){P[z]=i;++z;if(a){if(x[i]!=a)_ 0;}else a=x[i];}}_ a;}Y L(){W(i,d,0)if(M()*N()*O())_ 0;_ 1;}Y main(){cin>>n>>c>>d;while(1){W(i,d,0)B=cin>>A[i]>>c;if(x[S()]){Z(!);_ 0;}x[S()]=T;T*=-1;if(!B)break;}W(i,p,0)i<n?s+="1":s+="0";do if(C()&&L()){C()==1?Z(X):Z(O);_ 0;}while(prev_permutation(s.begin(),s.end()));_ 0;}

ผลลัพธ์คือ: "X" (X wins), "O" (O wins) หรือ "!" (พยายามย้ายที่ผิดกฎหมาย)

นี่แค่แมปจุดลงในอาร์เรย์แบบเส้นตรงและตรวจสอบชุดย่อยที่เป็นไปได้ทั้งหมดของขนาด n ก่อนเป็นค่าคงที่ที่ X หรือ O แล้วจึงอยู่ในบรรทัด ในการตรวจสอบว่าอยู่ในบรรทัดพิกัดของจุดในแต่ละชุดย่อยจะถูกตรวจสอบทีละครั้ง พวกเขาแต่ละคนจะต้องเพิ่มขึ้นจาก 0 เป็น n-1 ลดลงจาก n-1 เป็น 0 หรือค่าคงที่ คะแนนจะถูกเรียงตามลำดับในอาร์เรย์แบบเส้นตรงดังนั้นจึงเหมาะสมที่จะเรียกพิกัดเพิ่มขึ้นหรือลดลงสำหรับชุดของจุดที่กำหนด

ขอบคุณ Howard ที่ชี้ให้เห็นข้อผิดพลาดร้ายแรงในรุ่นแรก

ในความสมัครสมานกับ Quincunx ฉันต้องชี้ให้เห็นว่ามันจะเป็นการเลียนแบบถ้าคำตอบ C ++ ชนะ


1
ฉันคิดว่าในขณะที่คุณสามารถพูดได้ว่าการอยู่ในบรรทัดหมายถึงความก้าวหน้าทางเลขคณิต แต่มันก็ไม่ได้เป็นไปในทางตรงกันข้าม (เช่น 0,2,4 จะไม่เป็นทางออกสำหรับมาตรฐาน 3,2 นิ้วเท้า)
โฮเวิร์ด

@Howard ขอบคุณ ฉันได้ทำการแก้ไข มันสายเกินไปแล้วที่ฉันจะเล่นกอล์ฟจนจบ แต่ฉันก็สามารถแก้ไขได้ (ฉันคิดว่า)
Eric Tressler

คุณสามารถตีกอล์ฟเพิ่มได้โดยใช้เอาท์พุตที่ต่างกัน คุณไม่ได้ที่จะบอกว่าหรือX wins O winsมันถูกต้องตามกฎหมายอย่างสมบูรณ์ในการส่งออก1หรือ2(หรือการเปลี่ยนแปลงอื่น ๆ ) ตราบเท่าที่คุณอธิบายในคำตอบของคุณสิ่งที่พวกเขายืนหยัดเพื่อ ดังที่ฉันพูด (เน้นเพิ่ม): " ระบุผู้ชนะ"
Justin

เสร็จสิ้น และถ้าฉันสามารถเรียนรู้วิธีการทำงานของผู้ประกอบการที่สามฉันสามารถบันทึกตัวละครไม่กี่ตัว
Eric Tressler

แล้วความสัมพันธ์ล่ะ
Justin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.