하스켈, 146 자
흥미로운 것들을 만들기 위해 설명해야 할 상태에 대한 입력 구조를 결정하게됩니다.
확인 :). 내 보드 표현은 126 자 중 하나입니다.
ĻŃŇʼnŊœŗřŚşšŢťŦŨųŷŹźſƁƂƅƆƈƏƑƒƕƖƘƝƞƠƤƳƷƹƺƿǁǂDždžLjǏǑǒǕǖǘǝǞǠǤǯDZDzǵǶǸǽǾȀȄȍȎȐȔȜȳȷȹȺȿɁɂɅɆɈɏɑɒɕɖɘɝɞɠɤɯɱɲɵɶɸɽɾʀʄʍʎʐʔʜʯʱʲʵʶʸʽʾˀ˄ˍˎː˔ ~ ˭ˮ˰˴˼̌
다음은 146 자의 해결책입니다.
main=interact$(\x->case(head x)of h|elem h "ĻŃœťŦŨųŷŹƁƂƅƈƕƠƤƳƿǂdžǞǤǵǾȀȳȿɁɅɑɒɘɝɠɤɵɽʀʐʽʾː˭ˮ˰˴˼̌"->"lose";h|elem h "ƏƝƞƹǁLjǑǝȍȺɆɈɶɾʎʸ"->"cat";h->"win")
그리고 haskell 스크립트로 작동하는 방법은 다음과 같습니다.
import Data.List (subsequences, (\\))
import Data.Char (chr)
-- A set of indexes [0-8] describing where on the board pieces of a single color have been played
-- For example the board "OxO;Oxx;xxO" is indexes [0,2,3,8]
type Play = [Int]
-- There are 126 filled tic tac toe boards when X plays first.
-- (This is a combination of 4 OHs among 9 places : binomial(9 4) = 126)
-- perms returns a list of all such possible boards (represented by the index of their OHs).
perms = filter (\x -> 4 == length x) $ subsequences [0..8]
-- We now create an encoding for plays that brings them down to a single char.
-- The index list can be seen as an 9 bit binary word [0,2,3,8] -> '100001101'
-- This, in turn is the integer 269. The possible boards give integers between 15 and 480.
-- Let's call those PlayInts
type PlayInt = Int
permToInt [] = 0
permToInt (x:xs) = (2 ^ x) + permToInt xs
-- Since the characters in the range 15-480 are not all printable. We offset the chars by 300, this gives the range
-- ĻŃŇʼnŊœŗřŚşšŢťŦŨųŷŹźſƁƂƅƆƈƏƑƒƕƖƘƝƞƠƤƳƷƹƺƿǁǂDždžLjǏǑǒǕǖǘǝǞǠǤǯDZDzǵǶǸǽǾȀȄȍȎȐȔȜȳȷȹȺȿɁɂɅɆɈɏɑɒɕɖɘɝɞɠɤɯɱɲɵɶɸɽɾʀʄʍʎʐʔʜʯʱʲʵʶʸʽʾˀ˄ˍˎː˔˜˭ˮ˰˴˼̌
-- Of all distinct, printable characters
uOffset = 300
-- Transform a PlayInt to its Char representation
pIntToUnicode i = chr $ i + uOffset
-- Helper function to convert a board in a more user friendly representation to its Char
-- This accepts a representation in the form "xooxxxoxo"
convertBoard s = let play = map snd $ filter (\(c, i) -> c == 'o') $ (zip s [0..]) :: Play
in pIntToUnicode $ permToInt play
--
-- Now let's cook some data for our final result
--
-- All boards as chars
allUnicode = let allInts = map permToInt perms
in map pIntToUnicode allInts
-- Now let's determine which boards give which outcome.
-- These are all lines, columns, and diags that give a win when filled
wins = [
[0,1,2],[3,4,5],[6,7,8], -- lines
[0,3,6],[1,4,7],[2,5,8], -- columns
[0,4,8],[2,4,6] -- diagonals
]
isWin :: Play -> Bool
isWin ps = let triplets = filter (\x -> 3 == length x) $ subsequences ps -- extract all triplets in the 4 or 5 moves played
in any (\t -> t `elem` wins) triplets -- And check if any is a win line
-- These are OH wins
oWins = filter isWin perms
-- EX wins when the complement board wins
xWins = filter (isWin . complement) perms
where complement ps = [0..9] \\ ps
-- And it's stalemate otherwise
cWins = (perms \\ oWins) \\ xWins
-- Write the cooked data to files
cookData = let toString = map (pIntToUnicode . permToInt) in do
writeFile "all.txt" allUnicode
writeFile "cWins.txt" $ toString cWins
writeFile "oWins.txt" $ toString oWins
writeFile "xWins.txt" $ toString xWins
-- Now we know that there are 48 OH-wins, 16 stalemates, and 62 EX wins (they have more because they play 5 times instead of 4).
-- Finding the solution is just checking to which set an input board belongs to (ungolfed :)
main = interact $ \x -> case (head x) of -- Only consider the first input char
h | elem h "ĻŃœťŦŨųŷŹƁƂƅƈƕƠƤƳƿǂdžǞǤǵǾȀȳȿɁɅɑɒɘɝɠɤɵɽʀʐʽʾː˭ˮ˰˴˼̌" -> "lose" -- This string is == oWins
h | elem h "ƏƝƞƹǁLjǑǝȍȺɆɈɶɾʎʸ" -> "cat" -- And this one == cWins
h -> "win"
(win|lose|cat) [xo]{9}
여기서 첫 번째 단어는 게임이 플레이어 x의 승리, 패 또는 고양이 (?)인지를 나타냅니다. 모든 상태를 나타낼 수 있습니다.