Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away