Tic Tac Toe:重複することなくすべての可能な位置を印刷します


8

対応するゲーム結果を含む、可能なすべての三目並べ位置を出力するプログラムを記述します。同じ位置の重複出力を避けてください。

プログラムは入力を受け取りません。

ルール:

  • 位置出力は、取られた正方形を使用する9文字XO空白の正方形を表す任意の非空白文字で構成されている必要があります。
  • 各位置は3行/列で印刷する必要があり、2つの位置の間の区切りとして空白行が含まれます。
  • 追加の空白/空白行/ボックス描画文字は歓迎されています
  • プレイヤーXが最初に
  • 結果は、のいずれかになります。

    • Xが勝った
    • Oが勝った
    • ドロー
    • ゲーム進行中

    対応する位置の近くに配置されている限り、位置の結果の適切な視覚化を、たとえば色付きテキストやテキスト注釈として自由に選択できます。

  • 回転またはミラーリングによって一方から他方を取得できる場合、位置は等しいと見なされます。重複した位置は印刷しないでください。(つまり、等価クラスのみを出力します。)
    たとえば、次のいずれかのみを出力します。
X••  ••X  •••  •••
•••  •••  •••  •••
•••  •••  X••  ••X

出力例:

•••
•••
••• -

X••
•••
••• -

•X•
•••
••• -

•••
•X•
••• -


[…]


XXO
OOX
XXO /

OXO
XXX
OXO X

ヒント: 765のポジションがあり、Xで91勝、Oで44勝、3ドローです。


同様の質問が以前に尋ねてきたが、これは異なっています。


2
PPCGへようこそ!PPCGのすべての課題には、勝者の基準が必要です。この課題の基準は何ですか?バイトカウントが最も短いプログラムが勝つのはコードゴルフですか?
user41805

落札基準を確認すると、すぐに再び開かれるはずです。まだポジションは数えていませんが、空のボードはa)必須b)禁止c)オプションですか?
Level River St

実現したばかりで、最短のコードが勝つとすでに言っていました。code-golfタグでの編集。マルチバイト文字を使用してコードを短縮するために特別に考案された言語がいくつかあるため、ここでは通常バイト数でスコア付けしますが、それほど興味深いものではありません。
Level River St、

@StephenSそれは違うことです。1バイトは0〜255の任意の値を持つことができます。このWebサイトは、32〜126の範囲の1バイト文字とその他のいくつかの文字のみを表示できます。256バイトのコードページは古くからあり、私自身もCの回答をコードページ437に投稿しています。UTF-8は、すべての自然言語に十分な文字数がなかったために発明されましたが、UTF-8は非テキストを処理するように設計されていませんランダムなバイトのデータ。私はesolangs.org/wiki/Scliptingのような言語を参照していました。これは、マルチバイトのアジア文字を広範囲に使用して、文字のスコアリングの抜け穴を悪用しています
Level River St

@LevelRiverStああ、おっと。情報をありがとう:)
スティーブン

回答:


5

ゼリー192の 179 168バイト

5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?
U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ
FSµ×’¬
ÑPµA_µọ9n1
,UŒDḢ$€;;ZS€f3,-3
Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ
Ça3Ŀa4Ŀ
3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶

オンラインでお試しください!(約30秒かかるので、しばらくお待ちください)。

使い方

高レベルの概要:

中間ステップでは、これはXを1、未配置を0、Oをとして格納し-1ます。プログラムはすべての3 ^ 9の可能性を生成し、3つの基準に基づいて有効な位置のみを保持します。

  • XはOより1または0多い。
  • XとOの両方が勝ったわけではありません。
  • Xが勝った場合、XはOより1つ多くなります。Oが勝った場合、OとXの数は同じです。

次に、プログラムは各ゲームの状態をすべてのローテーションとリフレクションで置き換え、すべての等価クラスのリストを取得します。これはほとんどの時間を要する操作です。

最初のゲーム状態は各同等クラスから取得され、勝者が計算されます。

これが発生する場所 行は読みやすいように番号が付けられています

1: 5ĿḢṠµFf0L¬ị⁾-/µ5ĿḢṠµ?          ••calculates who wins (output as -1 or 1) or draw ("-") or in game ("/")
                 µ5ĿḢṠµ?          - if(someone won based on line 5):
   5ĿḢṠ                             - return 1 if X won and -1 if O won
       µ                          - else:
        Ff0L¬ị⁾-/                   - return "/" if the game is in progress and "-" if the game is at a tied end-state
2: U,µṚ,µ€µ“æɗþƑ’DịFs3,µ€€Fs9s3$€Ṣ••outputs the equivalence class to a game state
   U,                             - list of game state [reflected horizontally, unaltered]
     µṚ,µ€                        - for each, replace with the list [reflected vertically,unaltered]
          µ“æɗþƑ’DịFs3,µ€€        - for each, replace with the list [rotated 90 degrees counter-clockwise,unaltered]
                          Fs9s3$€ - reformat into list of game states
                                 Ṣ- Sort
3: FSµ×’¬                         ••outputs truthy iff there is the right number of `X`s to `O`s (condition 1)
   FS                             - d = number of `X`s minus number of `O`s
     µ×’                          - d*(d-1): falsey iff d is 0 or 1
        ¬                         - logical not, to return truthy iff d is 0 or 1
4: ÑPµA_µọ9n1                     ••outputs truthy iff there is the right number of winners (condition 2)
   Ñ                              - the winners. [-3,3] is what we want to return falsy on
    PµA_µ                         - 18 on [-3,3] and 0 otherwise
         ọ9n1                     - not divisible by 9 exactly once: 0 on [-3,3] and 1 otherwise
5: ,UŒDḢ$€;;ZS€f3,-3              ••outputs the number of times each player won.
   ,UŒDḢ$€;;Z                     - the diagonals, rows, and columns of a board
             S€                   - sum of each. Returns -3 or 3 iff the line is only 1s or -1s
               f3,-3              - filter out, keeping only 3s and -3s
6: Ç,SS€µṪµṪCµSṠ‘µ?÷Ḣ             ••return truthy iff the winner corresponds to the respective numbers of X and O (condition 3)
   Ç,SS€                          - list of winners and how many more Xs than Os there are
             µSṠ‘µ?               - if O won, then
        µṪ                          - how many more Xs than Os there are
                                  - else:
          µṪC                       - the complement of how many more Xs than Os there are
                   ÷Ḣ             - deal with no one winning
7: Ça3Ŀa4Ŀ                        ••return truthy iff the game state meets all three conditions
   Ç 3Ŀ 4Ŀ                        - the three conditions: on line 3,4, and 6
    a  a                          - joined by logical ANDs
8: 3ṗ9_2s3$€ÇÐf2Ŀ€QḢ€µ;ÑFµ€µ3Ḷ’,“O¤X”yµ€Fs10µs3Gµ€j⁾¶¶ ••do everything
   3ṗ9_2                        - all possible game states, with -1 for O and 1 for X
        s3$€                    - turn into two-dimensional game boards
            ÇÐf                 - filter based on line 6: if the board meets all three ocnditions
               2Ŀ€Q             - generate the equivalence classes for each and remove repeats based on line 1
                   Ḣ€           - get the first board from each class
                     µ;ÑFµ€     - append the winner to each board based on line 1
   µ3Ḷ’,“O¤X”yµ€                   - map each -1, 0, and 1 to the proper `O`,  `¤`, and `X`.
                Fs10µs3Gµ€         - format each board- winner combos
                          j⁾¶¶     - join the combos by double-newlines

2

Ruby、305バイト

19683.times{|i|c=(i%3).to_s 
s=(9**8+i/3*6562).to_s(3)
w=0
t=(0..3).map{|j|r=s[1+j*2,9]
w|=1<<r[0..2].sum%8|1<<(c+r[j/2]+r[4+j/2]).sum%8
[r,r.reverse].min}.min
v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]
w&=65
b=v.sum%51
w<65&&b>w/64&&b<3-w%2&&t==s[1,9]&&puts(v.tr("012","X.O"),w<1?v.include?(?1):w%31,"")}

これは他の回答と同様に機能し、すべての3**9ボードを生成してから有効なボードを除外します。内部的には0=X 1=. 2=O、出力内の3進数を使用しています。c中心の可能な3つs3**8 = 6561値と、境界の値を繰り返します。i/33進数の文字列表現に変換する前に、6562すべての桁を複製するために乗算し3**16、該当する場合は先行ゼロがあることを確認するために、1で始まる数値を追加します。w勝利条件です-これをゼロに設定します。

各ボードについて、4桁の数字の回転繰り返しs、境界を表す現在の8桁の3進数の字句的に最も低いバージョンを見つけます。同時に、最初の3桁(現在のローテーションの一番上の行)のASCII値を追加し、これを使用して勝利を確認します。また、ASCII値cと、正反対の数字のペアを追加して、センターで勝利したかどうかを確認します。

出力が有効かどうかを確認します -1のビットと64のビットのw両方が設定されている場合は、両方が有効です-これは無効です。XとOのバランスを確認します(勝者がいない場合は、XとOが等しいか、Xが1つ多い可能性があります。ただし、ゲームが勝った場合、勝者が最後に残っている必要があるため、可能な値は1つだけです。)同じボードの異なる回転を表示しないようにするには、境界の字句的に最も低いバージョンがの現在の値に対応する場合にのみ出力しますs[2,9]

シンボルを指定して、ボードを出力しますtr("012","X.O")。ボードの下にゲームのステータスが表示されます。w = 0の場合、これはtrueまだ空のマス(ゲームが進行中)でありfalse、ボードがいっぱいである場合です。場合はwゼロ以外の我々の出力である1プレイヤー1(X)が勝利した場合や、64%31==2プレイヤー2(O)が勝った場合は。

未ゴルフ

19683.times{|i|                             #check 3**9 possibilities
  c=(i%3).to_s                              #centre square: 0=X, 1=. 2=O 
  s=(9**8+i/3*6562).to_s(3)                 #perimeter:multiply i/3 by 3**8+1 to duplicate digits, add 3**16 to give a 1 at left side to ensure leading zeros
  w=0                                       #set w=0 to clear wins (1´s bit holds win for X, 64´s bit holds win for O)
  t=(0..3).map{|j|                          #build an array of 4 different rotations of the perimeter
     r=s[1+j*2,9]                           #by taking different 9-character slices of s
     w|=1<<r[0..2].sum%8|                   #add ascii codes mod 8 for top row of current rotation, take sum modulo 8 to give sum of digits. set a bit in w (we only care about bits 0 and 6)
        1<<(c+r[j/2]+r[4+j/2]).sum%8        #do the same for one of the 4 lines through the centre. if j/2=0 check diagonal, if j/2=1 check horizontal/vertical. 
     [r,r.reverse].min}.min                 #add to the array the lexically lowest version(forward or reverse) of the current rotation. When the loop ends, find the lexically lowest version overall and assign to t.
  v=t[0..2]+$/+t[7]+c+t[3]+$/+t[6]+t[5]+t[4]#format the output into a square 012\n 7c3\n 654
  w&=65                                     #clear bits 1 through 5 of w, leave only bits 0 and 6 which are the ones of interest.
  b=v.sum%51                                #valid values of sum of ascii codes in output are 461 (equal 0's and 2's) and 460 (one more 0 than 2). Take modulo 51 to reduce these values to 1 and 2       
  w<65&&                                    #if a maximum of one player has a winning line (not both) and
  b>w/64&&                                  #b must be 1 or 2 (only 2 permitted if O's won)
  b<3-w%2&&                                 #b must be 1 or 2 (only 1 permitted if X's won)
  t==s[1,9]&&                               #s[2,9] is the lexically lowest version of the current board (to avoid duplicates) then 
  puts(v.tr("012","X.O"),                   #output the board, subsituting internal "012" characters for external "X.O"
  w<1?v.include?(?1):w%31,"")               #if nobody won, output true if game in still in play (1's present on board) else false
}                                           #if there is a winner, output (player) 1 for X, (player) w%31=2 for O. Also output a blank line.

チェックスキーム

以下の図は、ローテーションのスキームを示しています(そして、勝利のチェック、大文字で)。図は回転せずに表示されます。4つの異なる回転は、の二重コピーからの部分文字列として取得されi/3ます。各図の周囲の3つの連続した大文字(現在の回転の「上」)は、9文字の部分文字列の最初の3文字です。回転ごとに、9文字の反転(AEまたはCG軸を中心とした斜めフリップ)も試行されます。ボードは、の現在の値i/3がすべての回転とミラーの字句的に最も低い場合にのみ出力されます。

 ABC    abC    aBc    Abc 
 hZd    hZD    hZd    HZD
 gfE    GfE    GFE    Gfe

2

Pythonの2648の 620バイト

import re
M=re.match
x='X';o='O'
R=lambda b,z=[6,3,0,7,4,1,8,5,2]:''.join(b[z[i]]for i in range(9))
p='XXX......|...XXX...|......XXX|X...X...X';q=p.replace(x,o)
def e(b):c=b.count;d=c(x)-c(o);w=M(p,b)or M(p,R(b));v=M(q,b)or M(q,R(b));return 0 if d not in[0,1]else 0 if w and v else(x if d==1 else 0)if w else(o if d==0 else 0)if v else'.'if'.'in b else'/'
h=set()
for n in range(3**9):
 b=reduce(lambda a,v:('.XO'[a[1]%3]+a[0],a[1]/3),range(9),('',n))[0]
 if b not in h:
	u=e(b)
	if u:print'%s\n%s\n%s %s\n'%(b[:3],b[3:6],b[6:],u)
	h.update(reduce(lambda a,v:a+[R(a[-2]),R(a[-1])],range(3),[b,R(b,[2,1,0,5,4,3,8,7,6])]))

オンラインでお試しください!

おそらく、このアプローチでは、ちょっとしたゴルフが可能です。しかし、多くはありません。

編集:Thxからovsへ、28バイトの増加を指摘した。アルテミスファウルの 3人

ゴルフではないコード

ここでの基本的な考え方は、3 ^ 9 = 19683の可能なボードエンコーディングのそれぞれをブルートフォースにします。エントリが重複しないように、すでに調査済みのボードの共役(回転と反射)を追跡します。少なくとも、有効なボードには、XとOの数が等しいか、XがOよりも1つ多い必要があります。Xの勝利とOの勝利の両方を持つことはできません。加えて、いくつかの厄介な制約。

import re
from collections import Counter

FLIP_XFRM = [2,1,0,5,4,3,8,7,6]
ROT_XFRM = [6,3,0,7,4,1,8,5,2]

def xfrm(b, xf):
    return ''.join(b[xf[i]] for i in range(9))

def flipIt(b):
    return xfrm(b,FLIP_XFRM)

def rotIt(b):
    return xfrm(b,ROT_XFRM)

def conjugates(b):
    conj = [b, flipIt(b)]
    for i in range(3):
        conj += [rotIt(conj[-2]), rotIt(conj[-1])]
    return conj

def tttToB(n):
    b = ''
    for i in range(9):
        b = '.XO'[n %3]+b
        n /= 3
    return b

def printBoard(b,outcome='.'):
    print '%s\n%s\n%s %s\n' % (b[:3],b[3:6],b[6:],outcome)

def evalBoard(b):
    c = Counter(b)
    if c['X']-c['O'] not in [0,1]:
        return False

    p1 = 'XXX......|...XXX...|......XXX|X...X...X'
    p2 = p1.replace('X','O')

    br = rotIt(b)
    w1 = re.match(p1,b) or re.match(p1,br)    
    w2 = re.match(p2,b) or re.match(p2,br)    
    if w1 and w2:
        return False

    if w1:
        return 'X' if c['X']==c['O']+1 else False

    if w2:
        return 'O' if c['X']==c['O'] else False

    if '.' in b:
        return '.'
    else:
        return '/'

def main():
    history = set()
    for m in range(3**9):
        b = tttToB(m)
        if b not in history:
            outcome = evalBoard(b)
            if outcome:
                printBoard(b,outcome)
            history.update(conjugates(b))

main()

私はあなたが必要とはしません Counter。置き換えることができますc=b.count;d=c(x)-c(o)
ovs '28

@ovs:とても注目!
Chas Brown

そんなに長い returnすることができreturn 0if d not in[0,1]else 0if w and v else(x*(d==1))if w else(o*(d==0))if v else'.'if'.'in b else'/'
ザカリー

古い投稿は知っていますが、これは623バイトのようです。インデントの2番目のレベル(2つのスペース)を620バイトの単一のタブに置き換えることができます。これを行うつもりですか?
アルテミスはまだSEを信頼していません

@ArtemisFowlうん、これは私がTIOを発見する前でした-カウントエラーを作るのは簡単です!
Chas Brown、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.