Створіть n до d-tic tac toe win-checker


13

Створіть найкоротшу програму, щоб перевірити, хто переміг у грі n d tic tac toe.

Ваша програма повинна працювати, коли 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):

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

І так далі.

Перемога (Якщо ви зіграли достатньо багатовимірного тик-нога, це те саме.)

Для того щоб мати виграш, один гравець повинен мати всі сусідні квадрати вздовж лінії. Тобто той гравець повинен мати nходи по лінії, щоб бути переможцем.

Суміжні:

  • кожна плитка - крапка; наприклад (0,0,0,0,0) - точка вd=5
  • сусідні плитки - це плитки, вони є обома точками на одному одиничному d-кубі. Іншими словами, відстань Чебишева між плитками дорівнює 1.
  • Іншими словами, якщо точка pприлягає до точки q, то кожна координата p, яка відповідає відповідної координаті, qвідрізняється від неї не більш ніж одиницею. Крім того, принаймні, пара координат відрізняється рівно на одиницю.

Рядки:

  • Лінії визначаються векторами і плиткою. Рядок - це кожна плитка, потрапила в рівняння:p0 + t<some vector with the same number of coordinates as p0>

Вхід :

Вхід буде STDIN. Перший рядок введення буде двома цифрами nі dу формі n,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-кубі?
Комінтерн

1
@Comintern Як це (я, мабуть, врахував пояснення. Можливо, напевно, буде простіше).
Джастін

Примітка: визначення, яке ви дали для сусідніх плиток, не є еквівалентним (тобто відстань на Манхеттені не дорівнює одиниці).
Говард,

Більше того, ви повинні визначити, що nдля перемоги потрібні рухи по лінії. (Вибачте за те, що не розміщували ці зауваження в пісочниці, але я навіть не встиг його побачити там, оскільки він був розміщений так скоро після пісочниці.)
Говард,

1
Я відчуваю, що в Пролозі має бути дуже коротке рішення ...
Нейт Елдредж

Відповіді:


3

Пітон, 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 виграв, і, означає, що було зроблено недійсний хід.


Деякі речі: змінити import *на import*. Використовувати як 1для True, так і 0для False (видалити Tта F). return -1можна return-1(перевірити видалення пробілів). Перейменуйте свої методи в єдині методи char. Ознайомтеся з порадами для більш оптимізації.
Джастін

О, дякую, я не знав, що ти можеш зробити щось із цього (а саме, прибрати пробіл між поверненням і -1)
foota

Я трохи пограв у гольф за вашим кодом (це може бути не всім дійсним). Результат тут: ideone.com/Ld2jAH . Будь ласка, перегляньте свою відповідь ще раз і скоротіть код наскільки це можливо. Питання щодо підказок python дуже корисно
Джастін

@foota Ви можете зробити if l<>q:замість цього if not l==q:.
mbomb007

3

Не відповідь - Java

Мені було цікаво побачити, як багато різних способів перемогти за певну n, d, тому я написав цей код, щоб перерахувати їх усіх.

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) ^ д - п ^ д).


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 виграє), "O" (O виграє) або "!" (незаконна спроба переїзду).

Це просто відображає точки в лінійний масив і перевіряє всі можливі підмножини розміру n, спочатку на постійність у X або O, а потім на пряму. Щоб перевірити наявність рядка, координати точок у кожному підмножині перевіряються по черзі; кожен з них повинен бути або зростаючим від 0 до n-1, зменшуючись від n-1 до 0, або постійним. Точки природно впорядковані в лінійному масиві, тому є сенс викликати координату, що збільшується або зменшується для заданого набору точок.

Дякую Говарду, що вказав на серйозну помилку в першій версії.

На знак солідарності з Quincunx я маю зазначити, що це було б пристрастю, якщо відповідь C ++ переможе


1
Я думаю, що, хоча ви можете сказати, що наведення в лінію передбачає арифметичну прогресію, це не буде навпаки (наприклад, 0,2,4 не буде рішенням для стандартного 3,2 тик-нога).
Говард

@Howard, спасибі Я вніс виправлення. Зараз мені вже пізно закінчити гольф, але я зміг це виправити (я думаю).
Ерік Тресслер,

Ви можете додатково пограти в гольф, використовуючи різні результати. Не потрібно точно говорити X winsабо O wins. Цілком законно виводити 1або 2(або якусь іншу варіацію) до тих пір, поки ви у своїй відповіді поясните, на що вони стоять. Як я вже сказав (наголос додав): " вкажіть, хто переміг".
Джастін

Зроблено. І якщо я можу дізнатися, як працює потрійний оператор, я можу зберегти кілька символів.
Ерік Треслер

А як щодо зв’язків?
Джастін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.