こんな夢をみた「太鼓折半」

こんな夢を見た。 私は辞書をひいていた。 「太鼓(たいこ)折半(せっぱん)」という語を調べようとしていた。

そして見付けた項目には「ひとつひとつは不幸な事例が重なって結果的に利益を得ること」とあった。

目が覚めてから調べてみたが、実際にはそんな言葉は存在しなかった。

私の夢に現れたからには私の脳で生み出された言葉なのだろう。 どういうメカニズムでこういう造語が、しかも合成元の言葉 (太鼓と折半) から全く想像できないような意味で作り出されるのか興味深いことだ。

Document ID: b05792fb9115aad482b40443f5415625

型を隠せるか

C++ ではクラス定義時に private としたメンバには外からはアクセスできない。 そのメンバへの参照やポインタを作って外へ漏らしたりしない限りあくまで内部的なデータである。 (メモリレイアウトを知っていれば無理矢理にアクセスすることは出来なくもないが、それは言語の範囲外の話ということでとりあえず置く。)

そして型についてもまたクラスの private 要素として定義することが出来る。 たとえば

#include <iostream>

class foo {
private:
  class bar {};
public:
  static bar make_bar(void) {
    return bar();
  }
  static void print_bar(bar) {
    std::cout << "bar" << std::endl;
  }
};

という定義を作ったときは foo::bar という型を隠したいという意図がある。 foo::bar という型に外からアクセスできないのだから、 foo::bar 型の変数を foo の外で作ることは出来ない。 foo::make_bar が返した値は捨てるか foo::print_bar が受け取る以外の使い方は出来ない。 …… C++03 までは。

C++11 以降では autodecltypeprivate な型も使える。

int main(void) {
  foo::make_bar(); // OK
  foo::print_bar(foo::make_bar()); // OK
  foo::bar x = foo::make_bar(); // foo::bar は private なのでエラー
  auto x = foo::make_bar(); // C++11 からは auto が使える
  decltype(foo::make_bar()) y = foo::make_bar(); // C++11 からは decltype が使える

  return 0;
}

autodecltype を通じてでも foo::bar という型を外で利用できなくする方法というのはあるだろうか?

Document ID: 10255bcb2ece0cf1d51420c8189eb2a2

Scheme でローカル定数

Common Lisp でローカルな定数を導入する構文を作ろうとする記事を読んだ。

Common Lispでローカル定数の構文 — #:g1

私は以前に似たようなことをやっていたことを思い出した。

以前に作ったマクロ define-constant は最終的に define に展開されるので、そのまま internal define に使っても機能はするのだが、あらためて let 系の形式でローカル定数を定義するマクロを書いてみることにした。

#!r6rs
(import (rnrs))

(define-syntax let-constant
  (lambda(stx)
    (syntax-case stx ()
      ((k ((var form) ...) body body* ...)
       (with-syntax
           (((t ...) (generate-temporaries #'(var ...))))
         #'(let ((t form) ...)
             (let-syntax
                 ((var
                   (make-variable-transformer
                    (lambda(stx2)
                      (syntax-case stx2 ()
                        ((set! v _)
                         (syntax-violation 'set!
                                           "attempt to assign constant"
                                           stx2
                                           #'v))
                        (_ #'t))))) ...)
               body body* ...)))))))

(let-constant ((x 1))
  ;;(set! x 2) ;; ← もし set! を試みたらエラーになる
  (display x)))

例として書いた定数 x は識別子マクロで、展開後には隠れた変数に置き換えられる。 識別子マクロは set! で代入されるときの展開形を特別に定義することも出来て、ここではそういう形になっているときは syntax-violation を使って構文エラーになるように定義した。

Document ID: d5f61355b4e55961f2af8517178d2c53

その心は

技術系の質問サイトや SNS(ソーシャルネットワークサービス) での技術コミュニティを見ている中で、技術的な困難さとは別に応え難いなと思う質問を見ることがある。 それは「A とは B のようなものですよね?」というような質問だ。 既に知っていることに当て嵌めて理解しようとするのが悪いわけではないが、どのくらい近ければ「ようなもの」と言ってしまってよいのかというのは微妙だ。

こういった質問の裏には「A を B と同一視してやってみたら上手くいかなかった」という背景が隠れていることがある。 仮にほとんどの部分で同じものであっても、だからこそ僅かな差の部分が躓きの原因になるので、そういったときに大雑把に「ようなもの」であるというのは何の(なぐさ)めにもならず、話が噛み合わない原因になると思う。

こういった比較のときには「ようなもの」ではなく「A は B と同じように C ですよね?」という風に、ふたつが近いと考える理由を提示するのが望ましいのではないだろうか。 もっとも、そこまで整理して考えることが出来るくらいならわざわざ質問しなくても解決できるかもしれないが。

Document ID: 98fa74bb0b34e6901c6ba4f119a68394

パイプでメモリをストリームにする

メモリ上にあるデータをあたかもファイルのように読みたいというのを以前に考えて、C++ のストリームクラスとして定義したことがある。

しかし、これはもちろん C++ でなければ使えない。 もう少し低水準の API を用いて実現できないかと考えたとき、 Windows API のパイプはほぼファイルと同じインターフェイスで使えることを思い出した。 シークが出来ないという制限はついてしまうが、それを除けば見掛け上はファイルと同じ形で処理できるのではないかと考え、実装してみた。

// memstream.h
HANDLE CreateMemoryFile(const LPVOID data, const DWORD data_size);
// memstream.c
#include <windows.h>
#include <process.h>
#include "memstream.h"

struct writer_args {
  HANDLE hWritePipe;
  LPVOID data;
  DWORD data_size;
};

static const int perround = 1024*64;

static void writer(void* args) {
  struct writer_args* wargs = args;
  char* data = wargs->data;
  DWORD data_size = wargs->data_size;
  HANDLE hWritePipe = wargs->hWritePipe;
  free(wargs);
  DWORD written_size;
  DWORD writing_size;
  
  for(DWORD rest=data_size; rest>0; data+=written_size, rest-=written_size) {
    writing_size = rest<perround ? rest : perround;
    if(!WriteFile(hWritePipe, data, writing_size, &written_size, NULL)) break;
  }

  CloseHandle(hWritePipe);
  _endthread();
}

HANDLE CreateMemoryFile(const LPVOID data, const DWORD data_size) {
  HANDLE rp, wp;
  BOOL result = CreatePipe(&rp, &wp, NULL, 0);
  if(!result) return INVALID_HANDLE_VALUE;
  struct writer_args* wargs = malloc(sizeof(struct writer_args));
  wargs->hWritePipe = wp;
  wargs->data = data;
  wargs->data_size = data_size;
  _beginthread(writer, 0, wargs);
  return rp;
}

これは以下のような要領で使うことが出来る。

#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include "memstream.h"

int main(void) {
  char* sample_str="Hello, this is file mapped memory sample";
  HANDLE mfh = CreateMemoryFile(sample_str, strlen(sample_str));
  int fd = _open_osfhandle((int)mfh, _O_RDONLY);
  FILE *fp = _fdopen(fd, "r");
  int ch;
  while((ch=getc(fp)) != EOF) putchar(ch);
  fclose(fp);
  return 0;
}

ウェブ上を検索してみるとスレッドを使わずに一気にパイプに書き込んでしまう方法を紹介しているものもある。 しかし、データ量が充分に小さいときを除いてはパイプのバッファサイズを越えてしまう可能性がある。 そのとき、少しづつでもパイプから読み出してデータを消費するのならばいずれは書込みも完了するのだが、シングルスレッドでは永遠に待つようになってしまう。 CreatePipe API の第四引数でパイプのバッファサイズを指定しても、あくまでヒントとして活用されるに過ぎず、その大きさのバッファを確保することを保証していないということに注意して欲しい。 パイプのバッファサイズ (としてヒントを与えた数値) より少ないデータ量しか書込まないからロックしないとは言い切れず、シングルスレッドで確実にロックしないようにする方法は (MSDN における CreatePipe に関する記述の範囲内では) 読み取れなかった。 そんなわけで、パイプを書き込む側はスレッドにするのが安全であると判断して上記のように実装した次第である。

Document ID: ecd99cc5c21bd06439374c829b044f4b

Chez Scheme でコンソールに日本語を出力する

プログラミング言語 Scheme の処理系のひとつである Chez Scheme仕様 (R6RS) が定める三種類の符号での入出力をサポートしています。

更に、独自拡張として iconv による変換も可能ですので、ほとんどどんな文字コードでも使えると思ってもいいでしょう。 もちろん、日本語の文字コードとしてよく使われる Shift_JIS やら CP932 やらにも対応しています。

さて、 R6RS では標準入出力用のポートにどんな文字コード変換器が結びついているか、あるいは結びついていないかは未定義ですが、 Chez Scheme では UTF-8 を採用しています。 しかし、 Windows の標準出力に UTF-8 のテキストを流し込んでもコンソール上では化けてしまいます。 それを解決するために CP932 に変換してからの出力を試みている事例を見掛けました。

ですが、これでは CP932 の文字セットに含まれない文字の情報が消えてしまいます。

WindowsUnicode 対応に積極的で、文字列のやりとりが必要な API はほぼ全て Unicode 版が存在しますし、コンソール関連の API についてもまたそうであるのですが、互換性の制約からか、標準出力経由でコンソールに表示する文字は CP932 と解釈してしまうようになっているのであって、コンソール関連の API を直接使えば Unicode のままで利用できます。

そこで、 Chez SchemeForeign Interface を用いて Unicode の文字をコンソールに表示するライブラリを作ってみました。 カスタムポートとして定義しており、このポートに対して出力することでコンソールに表示されます。 標準出力をリダイレクトしていてもコンソールに出力します。

(library (console-port)
  (export open-console-output-port)
  (import (chezscheme))

  (define dummy (begin (load-shared-object "kernel32.dll") 1))

  (define-ftype handle void*)

  (define open-existing 3)

  (define create-file
    (foreign-procedure __stdcall "CreateFileW"
      (wstring unsigned-32 unsigned-32 void* unsigned-32 unsigned-32 void*)
      void*))

  (define file-share-write 2)

  (define generic-write #x40000000)
  
  (define (get-active-console-buffer)
    (create-file "CONOUT$" generic-write file-share-write 0 open-existing 0 0))

  (define write-console
    (foreign-procedure __stdcall "WriteConsoleW"
      (void* wstring unsigned-32 u32* void*)
      boolean))

  (define (open-console-output-port)
    (let ((output-handle (get-active-console-buffer))
          (vsize (make-bytevector 4)))
      (define (write-to-console string start count)
        (let ((str (substring string start (+ start count))))
          (write-console output-handle str count vsize 0)
          count))
      (make-custom-textual-output-port "console" write-to-console #f #f #f)))
  )

使い方としては、 open-console-output-port 手続きが返すポートに書き込むだけです。

(import (rnrs)
        (console-port))

(let ((port (open-console-output-port)))
  (display "あいうえお\nかきくけこ\n" port)
  (display "♘♞♙♕♟♝♜♗♛♚♖♔" port)
  (flush-output-port port)) ;; フラッシュを忘れずに!

f:id:SaitoAtsushi:20170110051212p:plain

CP932 の範囲外の文字もきちんと表示できています。 ただし、コンソールに適用しているフォントがグリフを持っていない場合もあるので Unicode にある文字を全て確実に表示できるというわけではありません。

Document ID: fb260a71b629c76209cdc797c43c9bdd

ゲーム「ラビリンスの彼方」の戦闘システムが良かった

ニンテンドー 3DS のゲーム「ラビリンスの彼方」を購入した。 店頭で見てなんとなく表題が良いと感じて買ったのであって、どのようなゲームなのかは箱に書いてある以上の情報を調べなかったのだが、実際やってみると良くできているのだ。 襲ってくる敵を倒しながら迷宮の塔をのぼっていくゲームで、戦闘システムはジャンケンを元にした三竦みの属性を上手く活用している。

ウェブ上で評判を調べてみると戦闘が面倒くさいという意見もある。 しかし、むしろこのゲームは戦闘以外に見るべきものはあまりない。 迷宮にはそれほど凝った仕組みもなくただ延々と進んでいくだけである。 物語は迷宮を進ませる理由付け程度にしかない。 強いて言えば「跳ね橋」「鍵」「隠し扉」といっや要素はある。 跳ね橋は一方向からしか降ろすことが出来ないが、一旦降ろすと降りっぱなしであり、拠点との行き来を少し短かい距離で出来たりする。 錠で守られた扉は別のどこかで鍵を入手してからでないと開けられない。 隠し扉は一見して壁に見える場所を調べると通路だったりする。 隠し扉はそれほど隠れていなくて、割とわかりやすい。

戦闘システムについてであるが、この作品世界では「グーテシウム」「チョキロム」「パーティリウム」の属性を敵味方全員が持っているのが特徴である。 明らかにジャンケンをモチーフにしている。 ここではわかりやすいように「グー」「チョキ」「パー」と呼ぶことにしよう。 グーがチョキに勝ち、チョキがパーに勝ち、パーがグーに勝つのはジャンケンと同じだ。 つまり、たとえばチョキの属性を持つ者にグーの属性を持つ者が攻撃すれば威力が倍増する。 同じ属性であれば普通程度にダメージを与えることができ、相手側の方が強い属性であれば半分のダメージしか与えることができない。

では、なるべく相手の弱点で攻撃すればいいのだろうかといえばそうではない。 弱点を攻撃した (あるいはされた) ときにはダメージ分のエネルギーがその場に放出される。 たとえばチョキの属性を持つ者がグーの属性を持つ者に攻撃するとグーの属性のエネルギーがその場に放出される。 放出されたエネルギーはその属性の者の攻撃ターンに吸収されてダメージが回復する。 つまり、せっかくダメージを与えてもその後の攻撃順序によっては取り戻されてしまうことが有り得るのだ。 逆にダメージを受けても取り返せる可能性がある。 つまり、攻撃順序を調整するのが重要なのだ。 更に言えばこのゲームでの攻撃順序は戦闘終了時の状態が次の先頭に持ち越される。 同じ敵が連続して現れても自分の仲間たちの攻撃順序が違ってしまうので同じようには出来ない。 常によく考えることを強制されるので戦闘が単調にならないようになっている。

では、攻撃順序の調整はどうやるのかというと、攻撃の強さで選択する。 弱い攻撃なら次に攻撃するまでの時間は短かく、強い攻撃なら長くなる。 キャラを鍛えるとより強い攻撃を選択できるようになるが、常にめいっぱい強い攻撃をすればよいというわけではないということだ。

ゲームの分類としては、公式ページにはRPGと書いてあるが、レベルを上げて物理で殴るということが通用しない思考力を問われる戦闘システムはパズルゲームとも言えるだろう。

Document ID: 7200f15d5fbe5311d23d741ce63e380f