こちらにコメントしたHaskellのコードを、暇だったので久しぶりにCでもやってみる。
もとのHaskellのコード
Tick-Tack-Toe.hs
{-# LANGUAGE OverloadedStrings, BangPatterns, ViewPatterns #-}
import Data.Word (Word16)
import Data.Bits ((.|.),(.&.),setBit,testBit)
import Data.Ix (index)
solve :: String -> String
solve = go 'o' 'x' 0 0
where
go :: Char -> Char -> Word16 -> Word16 -> String -> String
go _ _ _ _ [] = undefined -- 勝敗が決まらないまま終了
go color oponent mhands ohands ((index ('0', '9') -> x):xs)
| testBit (mhands .|. ohands) x = "Foul:" ++ [oponent] ++ " won."
| or (map (\x -> x .&. mhands' == x) goals) = [color] ++ " won."
| (mhands' .|. ohands) == 0x3fe = "Draw game."
| otherwise = go oponent color ohands mhands' xs
where
mhands' = setBit mhands x
goals = map (foldl setBit 0) [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]]
main :: IO ()
main = getContents >>= mapM_ (putStrLn . solve) . lines
Cのコード
Tick-Tack-Toe.c
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
bool side = true;
uint16_t my_hands = 0x0000;
uint16_t oponent_hands = 0x0000;
#define g(a,b,c) ((1 << (a)) | (1 << (b)) | (1 << (c)))
static const uint16_t goals[] = { g(1,2,3), g(4,5,6), g(7,8,9), g(1,4,7), g(2,5,8), g(3,6,9), g(1,5,9), g(3,5,7) };
char *p;
for (p = argv[1]; *p; p++) { /* IOが面倒なので引数で受け取る。テストはxargsで */
uint16_t const *pp;
int n = *p - '0';
if ((my_hands | oponent_hands) & (1 << n)) {
printf("Foul: %c won.\n", side? 'x' : 'o');
goto fin;
}
my_hands |= 1 << n;
for (pp = goals; pp < goals + (sizeof(goals) / sizeof(*goals)); pp++) {
if ((my_hands & *pp) == *pp) {
printf("%c won.\n", side? 'o' : 'x');
goto fin;
}
}
if ((my_hands | oponent_hands) == 0x3fe) {
puts("Draw game.");
goto fin;
}
side = !side;
{ // swapってどこで定義されてたんだっけか.....
uint16_t tmp = my_hands;
my_hands = oponent_hands;
oponent_hands = tmp;
}
}
puts("No game."); /* 勝敗がつかないケース */
fin: return 0;
}
久しぶりのCだったのでいろいろグダってしまった。
型をいちいち明示しないといけないのが面倒と感じるあたり、だいぶ染まってしまったというか、Haskell以外愛せない体になってしまったというか...