Bercriber's Blog

すべて 日記 音楽 短歌 振り返り プログラミング

2025/01/14 17:26


三度白めば

今日はまだあなただけを知らない 今日初日の入り見に行きませんか

歩き疲れるくらいなら別にどうでもいいかな言えず僕も行く

一瞬の輝きの中に笑顔が 見覚えがある 思い出せない

水面に用がある あなたが跳ねると波紋がひとつふたつみっつも

三日ほど開けない夜に乗り込んで星は回るか月は沈むか

遠くから文字、声、顔へ続くほど言葉が日々を少し歪めて

冬空の白雲度々山隠し三度白めば麓にも雪


2024/12/31 18:17


2024年まとめ

利益38万、損失-56万、合計-18万

たしかエニカラで爆死。11月、12月はまったく見てすらいなかったらしい。ジェシー・リバモアの本を読んでそのメソッドでもやるかとか思ったけどまったく今まで学んできたことの正反対を行くらしく体が受け付けなかったというか、メソッドをやり切るメンタルがなかった。そんなことより10年前からnvidia買っておけばよかったんや。。。って思い続けてる。かなしい。

体調

腰痛からくるストレスによって精神状態がわるい。わるい。それいがいなにがあるだろうか。まぁこんな調子で脳機能が低下してる実感がある。スマホとキーボードの入力ミスの量が倍増してる気がする。視力も悪化してるので眼鏡の調整にいかなきゃいけないがいけない。行けない。眼鏡屋さん怖い。ことはないのに。行けない。

ゲーム

スプラ3、FF16、テラリア、モンハンワールドをやっていたらしい。FF16良かった。良かったね。テラリアは布団ちゃんのをみてやりたくなって、ラスボス倒してアルティメットソード的なやつ作って満足。モンハンは作業ゲーって感じだった。基本倒せるからたまに倒せないのがただのストレスであんまり楽しめなかった。スプラはロンブラ、デンタル、バケツなどを使ったりして、バケツに一番ハマってる。がらんどう先生の流麗な薙ぎ払いを見てからハマって、感度4.5でプロコン振り回してる。結論としては薙ぎ払いは4割くらいは当たらないので落ち着けという感じ。しばらくはバケツっていうか、二年以上経ってさすがに飽きそう。ちなみにXPは変わってない。なぜだ。

音楽

4曲作ってよかったんじゃないんでしょうか。あと一曲くらい頑張れたのでは。

プログラミング

ブログにYoutube埋め込めるようにしたくらいじゃね。gbe-hsもちょっといじった。以上。

短歌

月一で書いていた。なかなか自分が好きな詩を書けることが少ない。玉打てば当たる気がするので週一にするとか月二にするとかしたい気もする。それより曲を優先したい気もする。さぁさぁどうなる。

読書

買っただけで読んでない本が多い。何読んだのかもう覚えてない。

買い物

amazonに75万使ってて草。毎年60万ほどなわけだが今年はスマホとグラボがかさんでいるのだろう。Kindleに21万ほどで漫画に7万らしい。菓子に28万ほどらしいがそんなわけはない。まとめて記録してるので分割して総和は取れない仕組みです。正規表現のパターンを'^菓子$'にすると4万ほどなので最低でもこれくらいになる。

hoge

20代まとめみたいなやつ書いてて今見返すとおもろい。30代最初の一年ももうそろそろ終わるし人生もそろそろ終わる。しらんけど。

なにか言いたいことはないのか。

「風に自由を」を作れたのがとても良かった。大サビは自分でもよく歌っている。心に良い。曲ないし詩を書くこと、短歌を詠むことは人生の乱数で生成される文字列に引っかかる確率が上がることでもある。つまり出来事に文章が先行する場合がある。そのような時に自分のよくわからない言葉よ美しくあれよと祈った昔の自分がかけた魔法が花開くのである。そして散っていくことが、いや咲き誇こっていることが心の支えとなるのである。散る楽しみはまだ見逃してしまっているような気がする。しらんけど。

腰の問題をどうにかしないと本格的に仕事をやめるやめないになってくる。精神的な問題はある程度乗り越えられても、肉体的な問題は精神的な問題と相乗効果があるので、よりクソである。柔軟、筋トレを強化して、医療に頼る頻度も増やすべきである。病院嫌いなんだよね。

過去十年で仕事辞めたいと思わない年はなかった。しかし辞めなかった。しかしモラトリアムだったのだろう。本当に嫌だ。この先どうすればいいんだ。

ここに書いていない話がある。僕の頭の半分ほどを埋めている話だ。たぶん書くべきなんだろうけど書きたくない。心の空白を埋めるのに使われている話で埋めても埋めてもいつまでも満たされないけど笑みが溢れ出る。大切にすべき虚妄があるんだ。僕だけのありふれた。


2024/12/29 11:56


12月終わってて草

月間 草

まだ12月終わってなくて草。しかし冬休みは始まっただから片付けろブログを。

さあ、叔父が死んだ。爆死した。本当に文字通りに。南無三。 良き叔父だったし俺は良き甥だったのかな。まだ早いよ。ほんとに早い。どうか安らかに。

初っ端から仕事が辛かった。腰の状態がわるいのとそれからくる不安が強く、押しつぶされそうな椎間板とメンタルだった。俺のメンタルがヘルニア。とはいえ以外と乗り切れたが問題は今乗り切ったところで根本的な解決は見えず問題を抱えたままそれが発火する確率が日に日に高まっていくことだ。かなしい。

呪術廻戦と宝石の国の最終巻がでてとても良かった。宝石の国に関してはもう原初の物語は終わりエピローグのような世界の行方である。石は転がる方へ転がっていく。僕はまだ領域展開できるようになっていないし、螺旋丸もできないし、かめはめ波も打てない。どうしてなにもできないんだ。。。

曲作れなかった。叔父の訃報が届いた日にどうしようもない動揺をどうにかしようと詩を書いたらどうにかなった副産物として歌詞ができたのでそれを曲にするつもりだったが、あまりモチベが続かなかった。人の死をネタにするのもどうかと思わないでもないが、自分で歌える楽しい曲を基本的に作りたいので暗い曲になりそうなそれが難しかった。モチベが燃え尽きるまえにすこし打ち込んだやつをさっき聞き返したらすごいよかったので、まぁこれでいいんじゃないんですかの方針で作ろう。うーん。

スマホ変えた。Pixel7からiPhone16へ移行した。今のところすごく良い。キーボードにカーソルボタンがないのが地味に辛いくらいか。iOSでも空白長押しでも行けるが長押しをするラグが微妙だし、右方向の移動が物理的に少ない制限がある。画面の一番右に空白ボタンがあるわけでそこから右に指を移動しようものなら画面外。fly away。今のとこそれくらい。あと全部iPhoneがいい。ありがとうFaceID。もっと早くかえるべきだったのだ。この2年間無駄なことをしていたな。まあAndoridにはそれにはそれの良さがあるし、たぶんあるし、もしかしたらある。

Haskellでゲームボーイエミュレータが70ブクマいってて草だった。どうせおまえらやんねぇだろ。毎日俺のアクセスカウントしてるだけなんじゃないかみたいな2アクセスとかだったのが1000アクセスとかになってた。ホットエントリ人生で二度目だ。前はRustでテトリスでフロントエンドのエモい人が拾ったのが原因だったと思う。今回はアドベントカレンダーに参加したからだ。プログラミングちょっとできるのになんにもならないから、こういうのもたまにはいいな。だめぽ先生にReaderT使ったらとアドバイスをいただいたのでCPU部分だけ使ってみたら0.5秒ほど遅くなっただけだったから、これでいいやんと思ってリファクタリングしてMBCやLoggerなど全体のStateをReaderTモナドにしてみたら3秒/1.5倍遅くなって、うーん。まぁ十分なフレームレートでるだろうけどなんだかな。うーん。暇になったらPPUも書くか。APUは未だに仕様がわからん。ゲームボーイのエミュレータよりゲームボーイのソフトを書くhaskellのEDSL書いてみたいかも。

VCRのGTAが面白かった。ボッチ・ザ・ロックが面白かった。ダンダダンが面白かった。チ。が面白かったっといったところか。

冬休みできるだけ生活リズム変えないようにしたいと思いつつ寝る時間が同じでも睡眠時間が2,3時間増えることを僕はもう止められない。


2024/12/27 19:51


2024買って良かった物


2024/12/27 18:53


2024年読み始めて良かった漫画


2024/12/26 19:28


まだ落ちてる

逃げずとも逃げ切れるものだと気づく夕日から逃げるように帰宅

昨日見た落とし物がまだ落ちてる僕もお前もまだ見てるから

加湿器とエアコンの中揺れ動く湿度溺れるくらいでいいよ

暖房を消して眠れば寝つけずにつけて眠ればカラカラの喉

快晴の長いイントロにハイ!ハイ!とリズム合わずに白む山見る

言の葉が閉じてる本の中で舞うずっとずっといつまでも  開く

月を見失なった雲のない夜の「今日満月かもしれないのに」

見えないものは見えないと諦める たぶん眼鏡を変えれば済む話

あたたかい日陰にもれる日差しから夏の気配はずっと遠くに

生き方を 消えゆくまでの生き方を 消えて生き方を教えてください


2024/12/12 21:23


欠けたまま沈む

やがてくる悲しみが今日やってきてちゃんと悲しむみぎわのひとみ

三日月も欠けたまま静かに沈むそのうち満ちて僕もそのうち

ドライフルーツの噛めば溢れるもうドライじゃないフルーツの果汁

もう氷しかないアイスカフェラテを飲み干して氷も砕く冬

この空を支える柱全部折れ落ちてくる空を支える杖

さわやかな叔父の訃報が届く夜 あの眼鏡を真似して買ったな

最後まであなたの影にふさわしい光としての釜の火があったなら


2024/12/06 08:01


11月終わってて草

月間 草

まじでなんもしてない。新曲用の詩を一つ書いて音はまったく手を付けてない。バチコン楽しい。サーモンランやりすぎて腰を悪化させる。働きすぎて給料がいつもより多い。大統領選おもろい。新とびきりアボカドバーガーうまい。黒毛和牛バーガーそんなに。FF16クリアした。はい。腰が怖くて精神状態がわるい。体調がわるい。鼻水くしゃみ無限にでる。悲しい。

スプラやってる。楽しい。

ロンブラ6縦 pic.twitter.com/rIGFQRxwoQ

— 左右雨月 (@sauuzuki) November 20, 2024

バケツ、いい薙ぎ払い出た pic.twitter.com/dx5VPhTXvz

— 左右雨月 (@sauuzuki) November 26, 2024
      __  , パオーン
 .--()°'.' 
'|, . ,' 
 !_-(_\

2024/12/03 14:02


Haskellでゲームボーイエミュレータ

Haskell Advent Calendar 2024 3日目の記事です。

TypescriptやZigでゲームボーイエミュレータを書いたことがあったのでHaskellでも試して見ました。CPUまで書いて力尽きたのでゲームは遊べません。自分でゲームボーイエミュレータ書いてみたいという方はgbdev.ioを見ればだいたいなんとなくおおよそたぶんわかるかと思います。

エミュレータはCPUの命令を実行するたびにレジスタやメモリなどを逐次更新していくことになるのでミュータブルの方が効率が良いと思います。素直にIORefやVector.Mutableなどを使うのがよいと思うわけですが、StateMとLensを使えばミュータブルっぽいインターフェイスですっきり書けそうな気がしました。気がしたんです。

type CPU a = StateT CPUState (StateT MBCState (StateT LoggerState IO)) a

data CPUState = CPUState {
    -- レジスタなど
    _a, __f, ..., :: Word8,
    _pc, _sp, :: Word16,
    ...
    }

makeLenses ''CPU

-- 8ビットレジスタを2つ並べて擬似的に16ビットレジスターとしている
af :: Lens' CPUState Word16
af = lens get set
  where
    get cpu = toWord16 (_a cpu) (__f cpu)
    set cpu ww = cpu { _a = _a', __f = __f'' }
      where
        (_a',__f') = sepWord16 ww
        __f'' = __f' .&. 0b11110000

-- fレジスタの上位4ビットに各種フラグが格納されている
carry :: Lens' CPUState Bool
carry = lens get set
  where
    get cpu = testBit (__f cpu) 4
    set cpu b =
      if b then
        cpu { __f = setBit (__f cpu) 4 }
      else
        cpu { __f = clearBit (__f cpu) 4 }


-- CPUの命令
add :: OP -> CPU ()
add op = do
  a' <- use a -- aレジスタの読み取り
  w <- readOP8 op
  let (a'', c', h') = add8WithCarryHalf a' w
  a .= a'' -- aレジスタの更新

  -- フラグの更新
  zero .= isZero a''
  negative .= False
  half .= h'
  carry .= c'

call :: OP -> CPU ()
call op = do
  ww <- readOP16 WW -- ROM/プログラムから2byte/Word16分の即値を読んでる
  pc' <- use pc
  bool <- cond op -- carryフラグやzeroフラグのオンオフによってジャンプするかしないか
  when bool $ do
    push16 pc'
    pc .= ww

gbe-hs/MonadStackState

ログ用のStateとメモリやROMアクセスを仲介するMBC(メモリバンクコントローラー)用のStateも管理する必要があるためMonadスタックに積み上がってます。主にレコードのフィールドに置いたレジスタの更新にStateMとLensを使っています。

面白い点としては、self的なのがStateMによって隠蔽されてるので明示せずともよい所。各種フラグやレジスタのカスタムアクセサーがlens関数で定義できるのも良い点です。悪い点としては楽したいがためにレジスタの名前をaとかにしてるので一時変数の名前に困り、a'a''とかになって大変わかりずらい点(自分の名前付けが悪いが書いてるときは楽だった気もする)。

たとえばRustで似たような実装にすればselfの明示が必要になるかと思います。部分的に見ればHaskellのほうがスッキリしているようにも見えます。

fn add(&mut self, op: OP)  {
    let (a, carry, half) = self.a.add_carry_half(self.load8(op));
    self.a = a;
    self.set_carry(carry);
    self.set_half(half);
    self.set_negative(false);
    self.set_zero(self.a == 0);
}

fn call(&mut self, op: OP)  {
    let pc = self.fetch16();
    if self.cond_flag(op) {
        self.push16(self.pc);
        self.pc = pc;
    }
}

さて、上記の実装のような方針で一通り書いて動かしてみたらとても遅い。うちの7950xでもコンパイルに10秒くらいかかるのはいいとしても、実行でエミュレータ開発用のテストROMが落ちるまでに二分ほどかかるのはとてもかなしい(後述の実装では約6秒)。ここまで動くようにするのにStateMとLensと格闘した結果がこれだったのと、昔書いたdeno/typescript版が一秒で起動して約20秒で実行が終わっていたのもあり、しなしなになり力尽きました。正直テスト通ってないのでどこかでバグり散らかしているせいかもしれませんが。

少しの療養をとったあと、もう少しどうにかならんかと手を入れました。まずモナドスタックが重いのではないかと思いモナドスタックをフラットにしました。


-- 最初の実装
type CPU a = StateT CPUState (StateT MBCState (StateT LoggerState IO)) a

-- メモリアクセスのたびliftが発生する
read :: Address i => i -> CPU Word8
read i = do
  cycle += 1
  lift $ do
    reader' <- use reader
    reader' $ toInt i



-- モナドスタック潰した結果
type GB a = StateT GBState IO a

data GBState = GBState {
  _cpu :: CPUState,
  _mbc :: MBCState,
  _logger :: LoggerState
  }

read :: Address i => i -> GB Word8
read i = do
  cpu.cycleM += 1
  r <- use $ mbc.reader
  r $ toInt i

add :: OP -> GB ()
add op = do
  a' <- use $ cpu.a
  w <- readOP8 op
  let (a'', c', h') = add8CarryHalf a' w

  -- StateMの命令(.=)を複数並べていたのを(%=)一つにまとめている
  cpu %= 
      (a .~ a'')
    . (zero .~ isZero a'')
    . (negative .~ False)
    . (half .~ h')
    . (carry .~ c')

gbe-hs/global-state

モナドスタックを潰した結果として、先ほどのself的なのを書かなくてもいいという利点が消えました。CPUの命令がGB(GameBoy)モナドになっているためです。CPUのためだけの関数なのでスコープを限定したいのですが、実質グローバルステートで各Stateにアクセスできるようにするためこうなってます。(.=)を(%=)にしてStateモナドの命令をまとめているのでコストが下がってる気がしますたぶん。先ほどと同じテストROMを落ちるまで回して2倍くらい早い実行速度になりました。よかったねと言いたい所ですがとてもゲームがプレイアブルな速度にはなってはいなく、やはり悲しみとともに力尽きました。

しばらくの療養を終えたあと、さすがにhaskellがこんなに遅いわけない。ごりごり最適化すればC++並の速度がでるとかでないとかって昔見たような気がするぞわすれたけど。と思い直し、とりあえずすべてのレジスタをVector.Unboxed.Mutableにぶちこめばましになるやろの方針で書き直しました。

import Data.Vector.Unboxed.Mutable qualified as VM

newtype Store a = Store (VM.MVector (VM.PrimState IO) a)

data CPU = CPU { 
  mbc :: MBC,
  cpuLogger :: Logger CPULog,

  regs8 :: Store Word8,
  regs16 :: Store Word16,
  }


data CPUFlags = Carry | Half | Negative | Zero
  deriving (Enum, Show)

data CPURegisters8 = A | F | B | C | D | E | H | L | IME | Halt | Cycle | IsLogging
  deriving (Enum, Show, Eq)

data CPURegisters16 = SP | PC
  deriving (Enum, Show)

readReg8 :: CPU -> CPURegisters8 -> IO Word8
readReg8 (CPU {..}) r = readStore regs8 $ fromEnum r

readReg16 :: CPU -> CPURegisters16 -> IO Word16
readReg16 (CPU {..}) r = readStore regs16 $ fromEnum r

writeReg8 :: CPU -> CPURegisters8 -> Word8 -> IO ()
writeReg8 (CPU {..}) r n = writeStore regs8 (fromEnum r) n

writeReg16 :: CPU -> CPURegisters16 -> Word16 -> IO ()
writeReg16 (CPU {..}) r n = writeStore regs16 (fromEnum r) n

readFlag :: CPU -> CPUFlags -> IO Bool
readFlag cpu flag = do
  f <- readReg8 cpu F
  pure $ testBit f $ 4 + fromEnum flag

writeFlag :: CPU -> CPUFlags -> Bool -> IO ()
writeFlag cpu flag bool = do
  f <- readReg8 cpu F
  let f' = (if bool then setBit else clearBit) f (4 + fromEnum flag)
  writeReg8 cpu F $ f' .&. 0b11110000


add :: CPU -> Op8 -> IO ()
add cpu op = do
  a <- readReg8 cpu A
  n <- readOp8 cpu op
  let (a', carry, half) = addCarryHalf a n
  writeReg8 cpu A a'
  writeFlag cpu Carry carry
  writeFlag cpu Half half
  writeFlag cpu Negative False
  writeFlag cpu Zero $ a' == 0

call :: CPU -> OpCond -> IO ()
call cpu op = do
  nn <- fetch16 cpu

  bool <- condFlag cpu op
  when bool $ do
    pc <- readReg16 cpu PC
    push16 cpu pc
    writeReg16 cpu PC nn

gbe-hs/main

レジスタの値はWord8/16でだいたいいけるのでUnboxedが十分使えました。Stateモナドを撤廃したことでCPUレコードを引数として明示する必要が出てきました。レコードの中身がすべてIOVectorなので状態の引き回しについて考える必要がなかったのが楽でした。レジスターアクセスも直和型として定義したデータ型がそのままderiving(Enum)で配列の添字に使えるのでスッキリしました。

StateM/Lensを使えばスッキリ書けるんじゃないかという目論見は部分的によかったかと思いますが、実用的な速度はでなかったので結局素朴な実装になりました。先程と同じテストROMが約6秒で通るようになり最初の実装から約20倍早くなりゲームプレイもできるレベルであろうと安心して力尽きました。後から書いたRustの実装だと3秒だったので悪くないんじゃないんでしょうかねというかRustもなんか遅い気がしないでもない。

ほどよい歯ごたえだと思うのでみなさんもHaskellでゲームボーイエミュレータ書いてみませんか。λ...


2024/11/05 19:31


10月終わってて草

月間 草

10月なにしてたっけ。。。

眠れば眠るほど眠くなる」という曲を作った。ストリングスのスタッカートのコードで808のドラムでシンプルな感じで。詩がよくかけてる気がする。歌いごたえがあまりないボーカルメロディーなので次はもっとそんな感じで。前曲の大サビが歌いごたえがあるかんじだったので揺れ戻しでもある。

グラボ買い替えた。5万しないくらいで買った3070を15万で4070tiSuperに変えた。高すぎて草。おかげで使用率100%でも温度60くらいでファンも十分許容できる静かさなのでたいへん満足である。3070を売って3万、ポイントを使って6.5万、プライム感謝祭のポイント還元で1.5万、くらいの金策を使ったので実質4万くらいで買えたの感はある。良かったね。

PC版が発売されたFF16やってる。というかこいつのせいでグラボ変えるはめになった。びっくりするぐらいエグい音が3070から発せられていたので無理やんとなったしだい。ゆったりプレイしててまだクリアしてない。サブクエもやってない。あまりやりこみやる気がない。グラボを変えたせいでサンクコストバイアスというか義務感が漂っているが、ちゃんとおもしろいのでちゃんと良い。良いはずなんだよね。はい。クリアしたらDQ3HDかゼルダ姫かFF13か。

スプラ3あいもかわらずやってる。最近はリッタースコープと竹乙とカーボンローラーデコにはまってる。竹は玉があたらないし、カーボンは味方の塗り依存の立ち回りになっていてよくわからん。サーモンランもひさびさにカンスト付近までやり込んだ。オカシラ連合は倒せない。バチコンたのしみ。

日が沈むのが早くなって家路につく頃には暗くなってることが多くなってきた。夜道の運転は自分の車を買ってから夜間ドライブに出かけることが多くなったのでだいぶ怖さがなくなってきた。昨日も夜は綺麗だと思いながら運転して帰ってきた。田舎道に続く車のライトがきれいな良い夜だね。

歌集読んでる気がする。世界で一番素晴らしい俺の人の新作、沼の夢がとても良かった。やっぱこの人つぼだ。くそおもしろい。短歌で爆笑できるってほんとすごい。あと岡野さんのやつとか読んだ。今は月をテーマにした歌を色んな人から集めた歌集を読んでる。あと風にあたるも読んでる。積読消化したいし過去に読んだやつをまた読み直したいのだがはたして。。。

バケットハットをかぶるようになったが微妙かもしれないと思ったりそうでもなかったり。



21