LoginSignup
1
0

More than 5 years have passed since last update.

オフラインどう書く。Haskellで書いたのと同じ事をCでやってみた

Posted at

こちらにコメントした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以外愛せない体になってしまったというか...

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0