Building a memory game with Blocの手習い(Chapter 1)

これはSmalltalk Advent Calendar 2017の記事です。

Smalltalk絡みで何か書こうと思っていたけど、本職が火を吹いているので何もできず、そうかといってやり過ごすのも癪だ。
最近、Pharo Smalltalk界隈でBlocの話題がよく出ている気がする。小田さんのAdvent Calendarの記事にもなってるし。勉強会にも行ってないので何のことやら取り残された感を持っていたが、github にチュートリアルが出ていたので、それを記事を書くことで Bloc について勉強することにした。
ということで、元ネタは
https://github.com/pharo-graphics/Bloc
の中にある、
http://files.pharo.org/books-pdfs/booklet-Bloc/2017-11-09-memorygame.pdf
である。

Blocとは?

元ネタには、

Bloc is a low-level UI infrastructure & framework for Pharo.
Blockとは、Pharo のための低レベルUI+フレームワークのこと。

とある。Pharo のUIフレームワークには今までにもいろんなものが現れたが、そもそも Morphic とはどういう関係にあるのだろうか?よくわからない。

1.1 Memory game

元ネタでは MemoryGame booklet と紹介されているこのPDFには、Memory gameというゲームをBlocで作る過程が書かれているらしい。Memory gameは神経衰弱のようなゲームで、 n×n のゲーム盤に裏返しにカードが置かれており、2枚選んで表にして、同じものだったらプレイヤーの特点となり、違っていたら元に戻すというものらしい。
このチュートリアルの目標はMemory gameのモデルとUIを作成して、ちゃんと動くゲームにすること。最終的には以下のようなコードでゲームが動き始めるそうだ。

game := MgdGameModel new initializeForSymbols: '12345678'.
grid := MgdGameElement new.
grid memoryGame: game.
space := BlSpace new.
space extent: 420@420.
space root addChild: grid.
space show.

このコードはこのように説明されている。

  • まず、ゲームモデルを作って、各カードに対して1から8までの数を使うようにする。デフォルトではゲームモデルの大きさは 4×4 なので、8枚の異なるカードが必要となる。(1行目)
  • 次に、ゲームの要素を生成する。(2行目)
  • さらに、ゲームモデルとUIを結合させる。(3行目)
  • 最後に、ウィンドウを作ってゲームのUIを配置し(4〜6行目)、表示させる。(7行目)

ゲームモデル(game) とゲームのUI(grid)を、BlocのUI(space)に載せて動かすような感じだろうか。

1.2 Getting started

このチュートリアルは Pharo 6.1 を対象として作られている。6.1って最新版じゃん? Pharo は尖った針のようなSmalltalk処理系で、先に行くほど奈落の底に落ちやすくなるので、あまり最新版って使いたくない気がする。たいてい1年ごとに大きな変更があるので、様子を見ながら次のバージョンに進んでいるのだけど。まあ、良い機会なので最新版を使ってみよう。
Pharo 6.1 は以下のURLから得ることができる。
http://get.pharo.org/61+vm
といっても、ダウンロードページが現れるわけではなくダウンロードのためのbashスクリプトが手に入るだけなので、LinuxやMacOSなら、以下のようにして入手する。

$ mkdir pharo61
$ cd pharo61
$ wget -O- get.pharo.org/61+vm | bash
--2017-12-09 08:13:11-- http://get.pharo.org/61+vm
Resolving get.pharo.org (get.pharo.org)... 164.132.235.17, 2001:41d0:301::23
Connecting to get.pharo.org (get.pharo.org)|164.132.235.17|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3016 (2.9K)
Saving to: ‘STDOUT’
- 100%[========================================================================================>] 2.95K --.-KB/s in 0s
2017-12-09 08:13:11 (13.0 MB/s) - written to stdout [3016/3016]
Downloading the latest 61 Image:
 http://files.pharo.org/get-files/61/pharo.zip
Pharo.image
Downloading the latest pharoVM:
 http://files.pharo.org/get-files/61/pharo-linux-stable.zip
pharo-vm/pharo
Downloading PharoV61.sources:
 http://files.pharo.org/get-files/61/sources.zip
Creating starter scripts pharo and pharo-ui
On a 64-bit system? You must enable and install the 32-bit libraries
 Please see http://pharo.org/gnu-linux-installation for detailed instructions

Windows版がほしいなら素直に Pharo のサイトのダウンロードページから入手すればいいね。
Pharo 6.1を起動するには、ダウンロードされた中から pharo-ui を実行する。そうすれば以下のような画面が現れる。

Pharo をインストールしたらBloc 本体のパッケージをロードする。適当なリポジトリからloadするのが基本。
デスクトップの適当なところクリックするとWorld Menuが現れるので、Playgroundを選ぶ。

Playground画面に以下を入力(コピペ)する。

Metacello new
    baseline: 'Bloc';
    repository: 'github://pharo-graphics/Bloc:pharo6.1/src';
    load: #core.

入力したものをすべて選択して、右クリックでコンテキストメニューを出してDo itする。(LinuxならCtrl-D、MacならCommand-Dでもよし)いろいろプログレスバーが表示されるけど、何ごともなかったかのように終われば(エラーなどでなければ)OK。

1.3 Loading the Memory Game

本題のMemory Gameは、完全なものが github に公開されており、以下のようにして全コードをロードする。

Metacello new
    baseline: 'BlocTutorials';
    repository: 'github://pharo-graphics/Tutorials/src';
    load.

デスクトップの左クリックでWorldMenu を出して System Browser を開いたあと、左上の入力欄に memorygame と入力すれば、MemoryGame 関連のクラスカテゴリに絞り込まれる。
Bloc-MemoryGame カテゴリを選んだあと、MgExamples クラスを選び、Class ボタンでクラス側メソッドを表示させ、 open メソッドの左にある緑色のチェックマークのついたアイコンをクリックすると、完成したゲームを試すことができる。

ちなみに open を実行したら、エラーが出て実行できなかった。

Error: Cannot locate cairo library. Please check if it installed on your system

どうも64bit版のUbuntu Linuxにcairoライブラリがなかったせいらしいので、以下のように追加でパッケージをロードしたら問題なく動作した。

$ sudo apt install libcairo2:i386

ロードされたパッケージには Bloc-MemoryGame というクラスカテゴリとBloc-MemoryGame-Demo というクラスカテゴリに分かれている。前者はクラス名のプレフィクスが Mg で完全版のコードがあるのに対して、後者は Mgd でチュートリアルのコードが入っているようだ。
以上がチュートリアルの1章の内容となっている。2章以降も引き続き試して記事にしていくつもり。