直観について [from G+ 2015-01-09]

頭の中にはWebのように膨大な情報が詰まっている。直観とは、googleで検索を行うように、キーワードを使って情報を絞り込んでリストアップさせ、その中から適切なものを選ぶことではないか。

絞り込んだ情報の中からまたキーワードを見つけ、新たに得たキーワードと今までのキーワードを組み合わせてさらに情報を絞り込む。こういった再帰的な処理を行っているのではないか。

"記憶容量"の問題ではなく、"記憶要領"の問題である。「覚えられない」のではなく「引き出せない」のだ。引き出そうとすると、膨大な情報がHITしてしまって、うまく目的のものに辿りつかないのだ。うまく目的の情報を得るには、このキーワードにあたる部分が重要である。

熟練した人の頭の中には、局面そのものではなく、複数の似たような局面をまとめてパターン化したもの、たとえば文字列に対する正規表現のようなものが存在する(チャンクやテンプレート)。

キーワードは、言語だけでなく視覚や痛みなども含まれる。「手で覚える」とは、そういうことなのではないか。わざわざ将棋盤を出してきて手で指す行為は、人間の持つ五感を使って覚えることが効果的なのは、こういうことなのではないか。一見、効率の悪いように思われる行為でも、このキーワードを増やすことが記憶の中から適切なものを引き出すために重要なのではないかと思われる。

www.brain.riken.jp

この結果からすると、プロというのは、単純に駒配置のパターン(チャンクやテンプレート)だけでなく、価値の高い駒だけフィルターして評価するようなそいういう仕組みも別途持っていることになる。駒の価値によるフィルターは駒配置のパターンマッチと並列に行われているようだ。

web.archive.org

これはチェスや囲碁では見られない現象らしい。将棋は取った駒を使えるという他にはない特徴がある。そのことが関係しているのではないだろうか。だから駒の価値というものに重きを置いている。

詳細まで見ていないのでわからないが、単純に駒の種類だけでなく、自分が手にした時の価値と相手に取られた時の価値や、配置(特に相手の玉との距離)、ひもがついている、ついていない、守り用なのか攻め用なのか、についてもこの駒の価値に含めているんじゃないかと個人的に思う。受けモードと攻めモードがあり、受けモードの時には受ける場合の駒の価値を見る。この場合、自玉からの距離(実質の距離ではなく移動手数)が短いほど価値が高くなる。素人だと受けモードになった瞬間、遠い駒がまったく見えなくなるような現象だ。自玉だけでなく攻められている場所も関係するかも知れない。要するに絶対的な価値ではなく、相対的な価値。熟練者には飛車や角なんかよりも5五のと金の方が価値が>高いと判断する評価基準を持ち合わせているのではないかと思う。
特に穴熊での攻防では、この価値判断が顕著に現れるのではと思う。

これはまさに形勢判断そのものなのだが、コンピュータがやるように価値を計算するのではなく、検索をして価値を引き出すものがあるのだろう。

ひと目といっているのがこれなのか。

picとm4を使った電子回路の部品集[from G+ 2013-05-18]

ece.uwaterloo.ca


形式はSVGなので新しいが、根幹のpicとm4というのが古典芸。picはGNUのものではなく自作のdpic*1を使っている。

SVG出力というのが魅力的なのだが、dpicは微妙に言語仕様が違っており、カーニハン先生のマニュアルにあるものはそのままでは通らない。

TeXでの利用がメインのようだが、AsciiDocとかDocutilsとかのプラグインに組み込めば結構有力だと思う。

遊びでMoinMoinにpicプラグインを作って入れてみたが結構大変だった。

UMLGraphのバックエンドはpicなので使えそうなのだが、初期のpicって制限があってレターサイズ以上のものは表現できない。UMLGraphででかいシーケンス図とかつくろうとしてもぶった切れて使い物にならなかったりする。このあたりの制限を取り除けばそれなりに使えるツールになるのではと考えている。

*1:dpicのソースを見たがこれはCじゃない。PascalからCにトランスレートしている ;-p

Google+のサービス終了にともなって

そういえばこっちにもブログがあったのを忘れていた。
Google+のサービスが終了するので、あちらで書いたいくつかの記事をこちらに移そうかな。
大した内容でもないけど、消えるのもなんだかもったいない。

はてなダイアリーからはてなブログに移行

久々にはてなを見ていたら、はてなブログなるものを発見。
新しいもの好きなのでさっそく移行してみました。
ソースコードの行間が開きすぎているので後でデザイン調整しようっと。

joy2key

ジョイパッドの入力をキーボードのキーコードに変換するjoy2keyを試していたけど、window名の指定が面倒なのでフォーカスがあたったところ限定にしたオリジナル版を作ってみました。Shift, Control, Metaなどのmodifierがない簡易的なものです。

joy2keyのソースコードを見ればわかりますが、はっきりいっていまいちです。sleep(0.2)とか使い方間違ってるし。

はまっている方もいらっしゃるようです。
http://d.hatena.ne.jp/n9d/20080210/1202648836

$ ./myjoy2key -b "d c x s NoSymbol NoSymbol NoSymbol NoSymbol space Return a z" \
-a "Left Right Up Down"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>

#include <unistd.h>
#include <fcntl.h>

#if !defined(MYJOY2KEY_DEBUG)
#include <linux/joystick.h>

#include <X11/Xlib.h>
#include <X11/keysymdef.h>
#else
#include "myjoy2key_debug.h"
#endif

typedef struct {
    int pos_on;
    int neg_on;
    KeySym pos;
    KeySym neg;
} Axis;

typedef struct {
    char name[128];
    int fd;
    int naxes;
    int nbuttons;
    Axis *axis;
    KeySym *button;
} Joypad;

typedef struct {
    Display *display;
} Client;


void usage(const char *);
int joypad_load(Joypad *, const char *);
int joypad_exec(Client *, Joypad *);
int bind_axes(Joypad *, const char *);
int bind_buttons(Joypad *, const char *);
int gettok(const char *, char *, int, const char **);
int sendkey(Client *, KeySym, int);
void error(const char *, ...);


int main(int argc, char **argv)
{
    const char *progname;
    const char *devname;
    const char *axesstr;
    const char *buttonsstr;
    Joypad joypad;
    Client client;
    int opt;

    progname = argv[0];
    devname = "/dev/input/js0";
    axesstr = NULL;
    buttonsstr = NULL;
    while ((opt = getopt(argc, argv, "a:b:d:")) != -1) {
        switch (opt) {
        case 'a':
            axesstr = optarg;
            break;
        case 'b':
            buttonsstr = optarg;
            break;
        case 'd':
            devname = optarg;
            break;
        default:
            usage(progname);
        }
    }

    if ((client.display = XOpenDisplay(NULL)) == NULL)
        return EXIT_FAILURE;

    if (joypad_load(&joypad, devname) != 0)
        return EXIT_FAILURE;

    if (axesstr)
        if (bind_axes(&joypad, axesstr) != 0)
            return EXIT_FAILURE;

    if (buttonsstr)
        if (bind_buttons(&joypad, buttonsstr) != 0)
            return EXIT_FAILURE;

    while (joypad_exec(&client, &joypad) == 0)
        ;

    return EXIT_SUCCESS;
}

void usage(const char *progname)
{
    printf("%s [-a axes] [-b buttons] [-d devname]\n", progname);

    exit(EXIT_FAILURE);
}

int joypad_load(Joypad *joy, const char *devname)
{
    unsigned char v;
    size_t size;
    int i;

    if ((joy->fd = open(devname, O_RDONLY)) == -1) {
        error("open(`%s')", devname);
        return -1;
    }

    if (ioctl(joy->fd, JSIOCGNAME(sizeof(joy->name)), joy->name) < 0) {
        error("ioctl(name)");
        close(joy->fd);
        return -1;
    }

    if (ioctl(joy->fd, JSIOCGAXES, &v) < 0) {
        error("ioctl(axes)");
        close(joy->fd);
        return -1;
    }
    joy->naxes = v;

    if (ioctl(joy->fd, JSIOCGBUTTONS, &v) < 0) {
        error("ioctl(buttons)");
        close(joy->fd);
        return -1;
    }
    joy->nbuttons = v;

    printf("NAME    : %s\n", joy->name);
    printf("AXES    : %d\n", joy->naxes);
    printf("BUTTONS : %d\n", joy->nbuttons);

    size = joy->naxes * sizeof(*joy->axis);
    if ((joy->axis = malloc(size)) == NULL) {
        error("malloc(axis: %zu)", size);
        close(joy->fd);
        return -1;
    }

    for (i = 0; i < joy->naxes; i++) {
        joy->axis[i].pos = NoSymbol;
        joy->axis[i].neg = NoSymbol;
        joy->axis[i].pos_on = 0;
        joy->axis[i].neg_on = 0;
    }

    size = joy->nbuttons * sizeof(*joy->button);
    if ((joy->button = malloc(size)) == NULL) {
        error("malloc(button: %zu)", size);
        close(joy->fd);
        free(joy->axis);
        return -1;
    }

    for (i = 0; i < joy->nbuttons; i++)
        joy->button[i] = NoSymbol;

    return 0;
}

int bind_axes(Joypad *joy, const char *s)
{
    char token[80];
    const char *brkp;
    int n;

    brkp = NULL;
    for (n = 0; gettok(s, token, sizeof(token), &brkp); n++) {
        if (n >= joy->naxes * 2) {
            error("Too many AXES %d > %d * 2.\n", n + 1,
                  joy->naxes);
            return -1;
        }
        if (n & 1)
            joy->axis[n / 2].pos = XStringToKeysym(token);
        else
            joy->axis[n / 2].neg = XStringToKeysym(token);
    }
    if (n < joy->naxes * 2) {
        error("Too few AXES %d < %d * 2.\n", n, joy->naxes);
        return -1;
    }

    return 0;
}

int bind_buttons(Joypad *joy, const char *s)
{
    char token[80];
    const char *brkp;
    int n;

    brkp = NULL;
    for (n = 0; gettok(s, token, sizeof(token), &brkp); n++) {
        if (n >= joy->nbuttons) {
            error("Too many BUTTONS %d > %d.\n", n + 1,
                  joy->nbuttons);
            return -1;
        }
        joy->button[n] = XStringToKeysym(token);
    }
    if (n < joy->nbuttons) {
        error("Too few BUTTONS %d < %d.\n", n, joy->nbuttons);
        return -1;
    }

    return 0;
}

int gettok(const char *s, char *buf, int len, const char **brkp)
{
    const char *p;

    if (*brkp == NULL)
        p = s;
    else
        p = *brkp;

    if (*p == '\0')
        return 0;

    while (*p == ' ')
        p++;

    do {
        if (len <= 1) {
            error("Internal buffer too small.\n");
            return 0;
        }
        *buf++ = *p++;
        len--;
    } while (*p != ' ' && *p != '\0');

    *buf = '\0';

    *brkp = p;

    return 1;
}

int joypad_exec(Client *client, Joypad *joy)
{
    struct js_event e;
    KeySym key;
    Axis *axis;

    if (read(joy->fd, &e, sizeof(e)) != sizeof(e))
        return -1;

    switch (e.type & ~JS_EVENT_INIT) {
    case JS_EVENT_BUTTON:
        if ((key = joy->button[e.number]) != NoSymbol)
            sendkey(client, key, e.value ? KeyPress : KeyRelease);
        break;
    case JS_EVENT_AXIS:
        axis = &joy->axis[e.number];
        if (axis->neg_on && e.value >= 0) {
            sendkey(client, axis->neg, KeyRelease);
            axis->neg_on = 0;
        }
        if (axis->pos_on && e.value <= 0) {
            sendkey(client, axis->pos, KeyRelease);
            axis->pos_on = 0;
        }
        if (axis->neg != NoSymbol && e.value < 0) {
            sendkey(client, axis->neg, KeyPress);
            axis->neg_on = 1;
        }
        if (axis->pos != NoSymbol && e.value > 0) {
            sendkey(client, axis->pos, KeyPress);
            axis->pos_on = 1;
        }
        break;
    default:
        break;
    }

    return 0;
}

int sendkey(Client *client, KeySym key, int type)
{
    Display *display = client->display;
    XKeyEvent event;
    Window window;
    int r;

    XGetInputFocus(display, &window, &r);

    event.type = type;
    event.serial = 0; /* undef */
    event.send_event = 0; /* undef */
    event.display = display;
    event.window = window;
    event.root = DefaultRootWindow(display);
    event.subwindow = None;
    event.time = CurrentTime;
    event.x = 1; /* undef */
    event.y = 1; /* undef */
    event.x_root = 1; /* undef */
    event.y_root = 1; /* undef */
    event.state = 0;
    event.keycode = XKeysymToKeycode(display, key);
    event.same_screen = True; /* undef */

    XSendEvent(display, window, True, KeyPressMask, (XEvent *)&event);

    XFlush(display);

    return 0;
}

void error(const char *fmt, ...)
{
    int sverror;
    va_list ap;

    sverror = errno;

    fprintf(stderr, "Error: ");

    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);

    if (strchr(fmt, '\n') == NULL)
        fprintf(stderr, " %s\n", strerror(sverror));

    errno = sverror;
}