Thanks Driven Life

日々是感謝

Turnip 4.0.0 (Gherkin 6 対応) リリースしました

本記事の概要

Turnip の依存ライブラリの一つである Gherkin が 6 にメジャーバージョンアップしてそろそろ半年を迎えようとしています。 かなり遅れてしまいましたが、ようやく Turnip も Gherkin 6 に対応したので、その報告です。

また、 Gherkin 6 から新しいキーワードである Rule が追加されたので、その紹介もついでにやっていきます。

Turnip 4.0.0 の内容

https://github.com/jnicklas/turnip/releases/tag/v4.0.0

Gherkin 6 対応がメインとなります。

  • Gherkin 6 は 5 と API 互換性が無いため、Turnip もメジャーバージョンを上げました

    .feature ファイルのパース後の構造が変わっているだけなので、 Turnip::Node::xxxAPI には変更はありません

  • これまで使ってきた .feature ファイルはそのまま使えます

    Turnip を拡張して使っていなければ、バージョンアップに合わせての対応は必要ありません

Turnip そのものに新機能や改善があったわけではないため、普段使いであればあまり意識しなくても良さそうです。

Gherkin 6 の内容

Gherkin 6 では、下記キーワードが追加されました

  1. Rule
  2. Example (Scenario キーワードの別名)
  3. Scenario Template (Scenario Outline キーワードの別名)

2 と 3 はただのシノニム追加なので、1 の Rule について紹介していきます。

A new Rule keyword has been introduced, and acts as a grouping of one or more Example s - a new synonym for Scenario.

gherkin/CHANGELOG.md

これは例題を見るとわかりやすいです。

# https://docs.cucumber.io/gherkin/reference/#rule
# https://github.com/jnicklas/turnip/blob/v4.0.0/examples/gherkin6_syntax.feature

Feature: Gherkin 6 syntax

  Background:
    Given there is a monster with 2 hitpoints

  Scenario: Battle
    When I attack it
    Then the monster should be alive
    When I attack it
    Then it should die

  Rule: Battle with preemptive attack
    Background:
      Given I attack the monster and do 1 points damage

    Example: battle
      When I attack it
      Then it should die

  Rule: Battle with preemptive critical attack
    Background:
      Given I attack the monster and do 2 points damage

    Example: battle
      Then it should die

上記 feature を RSpec に落としてみたイメージはこんな感じ:

describe 'Gherkin 6 syntax' do
  before { send('there is a monster with 2 hitpoints') }

  describe 'Battle' do
    it do
      send('I attack it')
      send('the monster should be alive')
      send('I attack it')
      send('it should die')
    end
  end

  context 'Battle with preemptive attack' do
    before { send('I attack the monster and do 1 points damage') }

    describe 'battle' do
      it do
        send('I attack it')
        send('it should die')
      end
    end
  end

  context 'Battle with preemptive critical attack' do
    before { send('I attack the monster and do 2 points damage') }

    describe 'battle' do
      it do
        send('it should die')
      end
    end
  end
end

これまでの feature ファイルでは、Feature の下にある Background や Scenario が同じレイヤーにのみ存在を許されており、「このバックグラウンドはこのシナリオにのみ適用したいんだけど、ここに書くと全てのシナリオで発動しちゃうんだよなぁ」といったことが稀によくありました。その回避策として「別の Feature に分ける」「タグをつけて Step 側でなんとかする」といった対応が取られていたかと思います。

そこで Rule を使うと、そこらへんをよしなにいい感じに書けるようになる!みたいなやつだと思います!多分!!

まとめ

あけましておめでとうございます。本年もよろしくお願いします。

Emacs で動く NES エミュレータを作っている話

本記事は Emacs Advent Calendar 2018 の22日目の記事です。

成果物

まずは現時点 (12/22) での動作状況です。

https://github.com/gongo/emacs-nes

nestest.nes palette_pal.nes
f:id:gongoZ:20181222155809g:plain:w300 f:id:gongoZ:20181222160136j:plain:w300

使い方はいつか README の方に書きますが(いつか)、ざっと書くと:

  1. ソースコードもってくる
  2. nes*.el があるディレクトリに load-path を通す
  3. load-library nes
  4. M-x nes*.nes ファイルを選択

これで動くはずです。Byte Compile 推奨。

経緯

様々な言語で NES (= Nintendo Entertainment System) のエミュレータを実装する、というネタは昔からあります。私も何かしらの言語でやってみようかな? とボンヤリ考えたまま特に手をつけていませんでした。

そんな日々の中で参加した builderscon tokyo 2018 で、とある発表を見ました。

ファミコンエミュレータの創り方 - builderscon tokyo 2018

「何やっているのか良くわかんねえな?」と思いながらも「しかし面白いな!」という感想を得て、いよいよ自分でも何かで書いてみるかーという気持ちが再燃しました。

ちなみに「どの言語で実装するか?」ということですが、まだ誰も作っていなさそう*1Emacs Lisp でやってみることにしました。

記事の概要

  • 書いてあること
    • Emacs Lisp でそれっぽく動くところまでの話
  • 書いてないこと

動作するまでの話

時系列でふんわりと

1. まず ROM パーサの実装

.nes ファイルのフォーマット iNES の仕様どおりに読み込んでいきました。

2. CPU の実装

とにかく CPU が無いと始まらない! ということで CPU 周りに手をつけはじめました。

  1. 命令セットをとにかく Emacs Lisp に落としていく作業
  2. CPU 周りで必要な要素などを Emacs Lisp に落としていく作業

一通り落とし終わったので、いざ動くか試してみるぞ! と検証を開始しました。

検証に使用したのは

This is the best test to start with when getting a CPU emulator working for the first time.

と書かれるまでに便利な、 nestest.nes という「まずはこれ PASS したら次に進もうな」というテスト用 ROM です。

本来の nestest.nes は「コントローラ(ジョイスティック)でテストしたい CPU 命令を選んでテストを開始する」というものなのですが、この時点ではまだ画面やコントローラの実装できていません。そこで「コントローラの操作は無視して、ROM を読み込んで全ての CPU 命令に対するテストを実施する」というようなサンプルプログラムを書きました。

;; 当時のコードではなく、現状のコードで再現した形です
;; (この時はまだ ppu や interrupt は用意していなかったので)
(let ((cart (nes/cartridge-load "/path/to/nestest.nes"))
      (cpu (make-nes/cpu :interrupt (make-nes/interrupt) :ppu (make-nes/ppu))))
  (nes/cpu-set-working-ram cpu (make-vector #x0800 0))
  (nes/cpu-set-program-rom cpu (lexical-let ((cart cart))
                                 (lambda (addr)
                                   (nes/cartridge-read-from-prg-rom cart addr))))
  ;;
  ;; 画面から操作せず、テストだけを実行するために
  ;; nestest.txt の1行目の状況を開始地点(program counter)にセットしている
  ;;
  ;; memo: 長くなるのでここには書いていないが、 status register とかも
  ;;       1行目と合わせておく
  ;;
  (nes/cpu-reset cpu)
  (setf (nes/cpu-register->pc (nes/cpu->register cpu)) #xC000)

  (while t
    (let* ((r (nes/cpu->register cpu))
           (pc (nes/cpu-register->pc r))
           (opcode (nes/cpu-read cpu pc))
           (operand (nes/cpu-read cpu (1+ pc) :word))
           (inst (aref nes/instruction:MAP opcode))
           )
      (message "%04X %02X %s A:%02X X:%02X Y:%02X P:%02X SP:%02X"
               pc
               opcode
               (if (null operand) "    " (format "%4X" operand))
               (nes/cpu-register->acc r)
               (nes/cpu-register->idx-x r)
               (nes/cpu-register->idx-y r)
               (logior (lsh (if (nes/cpu-register->sr-negative r)  1 0) 7)
                       (lsh (if (nes/cpu-register->sr-overflow r)  1 0) 6)
                       (lsh (if (nes/cpu-register->sr-reserved r)  1 0) 5)
                       (lsh (if (nes/cpu-register->sr-break r)     1 0) 4)
                       (lsh (if (nes/cpu-register->sr-decimal r)   1 0) 3)
                       (lsh (if (nes/cpu-register->sr-interrupt r) 1 0) 2)
                       (lsh (if (nes/cpu-register->sr-zero r)      1 0) 1)
                       (lsh (if (nes/cpu-register->sr-carry r)     1 0) 0))
               (nes/cpu-register->sp r)
               )
      (nes/cpu-step cpu)
      )))

このプログラムを実行すると、下記のような結果が *Message* バッファに書き出されます:

C000 4C C5F5 A:00 X:00 Y:00 P:24 SP:FD
C5F5 A2 8600 A:00 X:00 Y:00 P:24 SP:FD
C5F7 86 8600 A:00 X:00 Y:00 P:26 SP:FD
C5F9 86 8610 A:00 X:00 Y:00 P:26 SP:FD
C5FB 86 2011 A:00 X:00 Y:00 P:26 SP:FD
C5FD 20 C72D A:00 X:00 Y:00 P:26 SP:FD
C72D EA B038 A:00 X:00 Y:00 P:26 SP:FB
C72E 38  4B0 A:00 X:00 Y:00 P:26 SP:FB
C72F B0 A204 A:00 X:00 Y:00 P:27 SP:FB
C735 EA B018 A:00 X:00 Y:00 P:27 SP:FB
C736 18  3B0 A:00 X:00 Y:00 P:27 SP:FB
C737 B0 4C03 A:00 X:00 Y:00 P:26 SP:FB
C739 4C C740 A:00 X:00 Y:00 P:26 SP:FB
C740 EA 9038 A:00 X:00 Y:00 P:26 SP:FB
C741 38  390 A:00 X:00 Y:00 P:26 SP:FB
C742 90 4C03 A:00 X:00 Y:00 P:27 SP:FB
C744 4C C74B A:00 X:00 Y:00 P:27 SP:FB
C74B EA 9018 A:00 X:00 Y:00 P:27 SP:FB
C74C 18  490 A:00 X:00 Y:00 P:27 SP:FB
...
...

あとはこの結果と、「 nestest.nespc=C000 以降の動きがこうなっていれば正解やで」が記載されている nestest.log を比較して、PC や各レジスタの値が同じまま最後まで到達したら CPU はひとまず実装終わり!

3. PPU の実装 (白黒・背景画像だけ)

ついに見える化を進めます。

ところで、Emacs で「指定した位置に、この色でピクセルを描画する」という実装を行う場合、様々な方法があると思います。 今回は 18日目の記事でも紹介されていた gamegrid.el を使用しました。 私自身も2年前に gamegrid.el で一ネタ 作っており、とりあえずこれでいいかーという気持ちで選定しました

nes-ppu.el

PPU の実装、ものすごく大変でした。 CPU と違って「目チェックしては修正して〜」の繰り返し*2。そんな PPU の実装を開始して一週間後、ついに…

ここまで来るとモチベーションも高まり、あとは勢いのまま突き進みました。

画面が使えるようになることで、他のテスト用ROMでも試せるようになり、更に便利に。

4. コントローラの実装

コントローラ操作はもちろんキー入力。キー入力と云えば Emacs の独壇場。特に問題もなく実装できました(2Pコンはまだ未実装なのですが)。

nes-keypad.el

コントローラも実装できたことで、以前テキスト比較でのみ使用していた nestest.nes も、ついに画面で結果を見ることに成功。

5. PPU の実装 (色有り・背景画像だけ)

そろそろ白黒から脱却する時期になりました。一気に実装

📝 当時は色テーブルが間違っており、色が変でした。

6. PPU の実装(スプライト画像)

背景画像とはまた別の計算が絡んできて一層混乱しました。

とはいえ、あとはひたすら微調整作業だったので、無事にそこそこ動作するまでもってこれました。終わり。

まだ実装できていないところ

1. スプライトの処理がまだ甘い

まだズレがある

f:id:gongoZ:20181222184432p:plain:w300

2. スクロール処理がおかしい

f:id:gongoZ:20181222155710g:plain:w300

この ROM は ギコ猫でもわかるファミコンプログラミング にある、背景画像スクロールの例題です。何かこう、移動がぎこちない。素直に左に進んで欲しい

3. 遅い

今のところ体感で 3 FPS ぐらいです。なんとか ギコ猫 がギリギリ動かせるぐらい(十字キーの左を押しっぱなしでこれぐらい):

f:id:gongoZ:20181222183547g:plain:w300

4. BGM

さすがに Emacs 単体では無理かもしれない

5. 縦横のサイズを調整するのが少し面倒くさい

gamegrid.el に限らず、Emacs で各ポジションに色つけたりする時は face や font を弄ると思います。 つまり、その位置にある文字の width と height が、そのまま NES エミュレータ側からみる「1ピクセルの width と height 」になります。

これの何が面倒くさいのかというと、基本的に使っているフォントは「縦のサイズ = 横*2」みたいなことが多いので:

f:id:gongoZ:20181222181533p:plain:w300

こんな感じで縦長になってしまいます( iTerm で 256 x 149 の様子。256 x 240 が領域なので、下の方が見えない)

仕方ないので、今のところ端末設定の「行間隔」に相当する設定を弄ってそれっぽく見えるように調整*3しています。(冒頭の画像とかはそれ)

f:id:gongoZ:20181222182238p:plain:w300

  • Emacs の設定だけでは上記のような行間隔設定ができない*4
  • おそらくそれ用(height == width)のフォントを用意すればいけるのかな…?

まとめ

深い解説のない、ただの開発日記みたいになりましたが如何でしたでしょうか。 取り組み始めて約2ヶ月(毎日やっていたわけではないですが)かかり、なんとかモノになったので良かったです。

難しいといえば難しいですが、やはり目に見えて良くなっていくのは開発してて面白いですね。 もう少しマシなゲームが動かせるようになったら、またどこかで報告します。*5

それでは、今年もお疲れ様でした。良い御年を

参考

*1:Lisp」という括りではいくつかありました https://news.ycombinator.com/item?id=8666976

*2:特にパターンテーブルの理解に時間をかけました。つまりどういうことやねん状態

*3:Emacs に限らず、端末に描画するタイプはここらへん調整が必要になりそう

*4:見つけきれてないだけかも。あると嬉しい

*5:吸い出し機買わないと…

年末調整Tシャツを作っています

最近は年末調整のことばかりを考えており、とはいえ実際に記入するのはもう少し先の話です。 息抜きも必要、しかしまったく離れるわけにもいかない。そんな気持ちでTシャツを SUZURI で販売しています。

各書類の詳しい説明は こちら(国税庁) から確認できます。

一例:

追記

買う人いるとは思わなかったんですよね…

Nokia Steel HR を1ヶ月使ってみた記録

ただの記録です

買ったもの

Nokia Steel HR 40mm モデルです

Nokia Steel HR - Withings ウォッチの各モデルの違いはどのようなものですか?

バッテリーについて

  • 前提

    • 継続心拍数モードは使っていない
  • 結果

    25日無充電でもまだ余裕ある

    日付 電池残量
    1/21 85% (購入時)
    2/15 8%

満タンから始めると1ヶ月ぐらいは持ちそう

Nokia Steel HR™ は、一回の充電で最大25日間使用可能ですが、使用可能な日数は継続心拍数モードの使用頻度により変動します。トレーニング中だけでなく、常時継続心拍数モードを使用すると、バッテリーの消耗がより増加します。

Nokia Steel HR - バッテリーの電池寿命はどれくらいですか?

着け心地

普段時計などはつけない(違和感気になるタイプ)が、着けた初日から問題なく睡眠に入れるぐらい

睡眠の記録について

だいたい23時あたりからは動き少ないと寝ている判定をされるっぽい

まとめ

SmartHR に入社していました

メリークリスマス(昨日)。皆様いかがお過ごしでしょうか。

去年は Emacs で雪を降らせていた 私ですが、今年も無事平和に過ごしております。

そんなこんなで2017年もそろそろ終わり。 今年は私の人生としては(かなりの)変化の年でもあったため、一年を軽く振り返りつつ、近況をご報告致します。

概要

2017年9月から SmartHR で働いています。職種はサーバーサイドエンジニア。 前職は PHP でしたが、今は Ruby on Rails をがんばっています。

以降、会社の説明はあまり無いので、そちらに興味ある方はこちらへお願いします

https://smarthr.co.jp/recruit

入社の経緯

2009年3月に大学院を卒業し、同年4月より沖縄の SIer (つまり前職)に新卒で入社。以降 PHP をやったりやらなかったりで気づけば2017年。 特に不満もなく(悪く言えばだらだらと過ごし)、また新しい年度が始まるんだなーという4月を迎えた頃

「あ、転職するか」

というモチベーションが一気に盛り上がりました*1。 この勢いを止めないようにしようと、次の職場を決める前にいろいろチーム内で引き継ぎなどをしつつ、スケジュールもだいたい決まった6月を過ぎたあたりで以下をツイートしました。

ありがたいことにいくつか声をかけていただきまして、良きタイミングでいろんな会社に遊びにいったり Skype などでお話を伺ったり。 いろいろありましたが最終的に現在の SmartHR でお世話になることが決定しました。

入社してどんな感じか

楽しいです。

「労務」という(私が思う)通常のエンジニアであれば直接接点のない領域に対してハックしていくという業務がとても新鮮で、良きです。 キャリアパスとしても、HR Tech という分野の最前線に立っていろいろ触れられるというのも強みだと思い、そこもモチベーションに繋がっています。

エンジニアチーム(に限らず他のチームも)凄い人ばかりで、日々勉強といった感じです。がんばりたい。

人見知りの私が慣れ親しんだ環境から離れて大丈夫か?と心配の方も居らっしゃると思います。 大丈夫、僕は元気ですということを示す、会社の人たちとの心温まるやりとりです。

業務以外

  • 人生初めての一人暮らし & 引越し(沖縄 → 東京) 。引越し前後はさすがにドタバタしていましたが、今はまったりしています。
  • 東京の勉強会やイベントにも顔を出しやすくなったけど、いざ現地にくるとなかなか行かないことがわかる
  • 前職は「夏はかりゆしウェア、冬はスーツ」という感じでしたが今は私服なので楽
    • スーツ時代も、服考えなくて良いというのはありましたが、ネクタイがつらかった

おわり

おまけ

初転職してあらためて知ったのですが、前職で一緒だったチームメンバーも、やっぱりみんな凄かったんだというのが再認識できた。そこが一番嬉しいかも。

*1:本当に何の不満も理由も無く、周りからも「急にどうした」みたいなリアクションをいただきました

builderscon tokyo 2017 に参加しました

完全に遅刻した


というわけで builderscon tokyo 2017 に参加しました。 去年は参加できなかったのですが、感想ブログとかを見て面白そうだなー今年は行きたいなーみたいな気分だったので良かった。

以下、雑に参加したセッションの感想

前夜祭(8/3)

撤退技術スペシャル祭り。うんうんそれも人生だよね

1日目(8/4)

2日目(8/5)


というわけ前夜祭もあわせて二日とちょっと。お疲れ様でした。楽しかったです。

個人的には朝食が美味しかったのも良かった。朝食最高!!

来年もあるなら是非参加したい

エクストリーム二度寝

説明しよう!!エクストリーム二度寝とは「朝、寿司を食ったあとに二度寝する」ことだ!!

実施例:

  1. 4:55 起床。諸々外出準備
  2. 5:30 築地市場大和寿司 到着。開店時間だが既に10人ぐらい並んでいて且つ店内は満席
  3. 5:55 店に入る
  4. 5:56 俺「おまかせで!」
  5. 6:05 職人「セットはこれで終わり」俺「おすすめ追加」「本マグロくってけ」「ひゅー♪」
  6. 6:10 店を出る
  7. 6:30 寝床に戻り、二度寝を開始する
  8. 8:30 起床

エクストリーム二度寝の欠点は起床後の出社欲が著しく低下することだが、本日僕はお休みです。

Current status

Wataru MIYAGUNIさん(@gongo)がシェアした投稿 -