パンドラム

宇宙船でコールドスリープから目覚めたら記憶障害で自分だけ
すぐ中尉が起きるけど同じく記憶障害
ブリッジに行こうとするけどスカイリムのファルマーみたいな怪物がうろついてて襲われる
女と言葉の通じない農夫とであって原子炉を再起動しに行く
途中でコックに捕まり地球が消し飛び狂ったクルーが残った人を皆殺しにした話を聞く
原子炉を再起動するけどファルマーの巣になってるので追いかけられる
中尉が狂ったクルーだったことが分かり、ついでに移住先の星についてるけど海に不時着し水没していることを知る
中尉と戦っている時に船を傷つけてしまい緊急脱出し地上に出られる


どう見てもファルマーやん

ソースコードに行番号

はてなブログのデザインとやらを弄ってソースコードに行番号を付けてみた
わりかしなんでも書けるのね、知らなかった
テーマ?変更したらええんかと思って色々変えてよく分かんなくなったけど
結局自分で書いた方が早いや(^^;

main = putStrLn "Hello World!"
<script>
var codes = document.getElementsByClassName("code");
for(var i = 0; i < codes.length; i++)
{
	var lines = codes[i].innerHTML.split("\n");
	var code = "";
	for(var j = 0; j < lines.length; j++)
	{
		if(j == lines.length - 1 && lines[j] == "") break;
		code += "<code>" + lines[j] + "</code>\n";
	}
	codes[i].innerHTML = code;
}
</script>
pre.code > code
{
    counter-increment: linenumber;
}

pre.code > code::before
{
    content: counter(linenumber) "|  ";
}

行番号との間の縦線が書けなくて適当やわ

switch対応

switch文に対応してみた
まだswitchは式にできてないので戻り値は返せないけども

とりあえず[x, xs]のxs部分にcdr相当を渡したいんだけど
めっちゃめんどくさいので単純に配列をGetRangeしてコピーすることにした
GetRangeはご丁寧にもMSDNにO(n)っすよって書いてあるけど、もうほんとめんどくさいしいいや

f:id:zenu:20170924230018p:plain

コンパイルした結果がこれ
わらっちゃうくらいザツい(^-^;

.method public static void  switch.show(class [mscorlib]System.Collections.Generic.List`1<int32> A_0) cil managed
{
  // コード サイズ       96 (0x60)
  .maxstack  7
  .locals init (int32 V_0,
           bool V_1,
           int32 V_2,
           int32 V_3,
           class [mscorlib]System.Collections.Generic.List`1<int32> V_4)
  IL_0000:  ldarg.0
  IL_0001:  call       instance int32 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Count()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.0
  IL_0009:  ceq
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  brtrue     IL_0017

  IL_0012:  br         IL_001c

  IL_0017:  br         IL_005f

  IL_001c:  ldloc.0
  IL_001d:  ldc.i4.1
  IL_001e:  clt
  IL_0020:  ldc.i4.0
  IL_0021:  ceq
  IL_0023:  stloc.1
  IL_0024:  ldloc.1
  IL_0025:  brtrue     IL_002f

  IL_002a:  br         IL_005f

  IL_002f:  ldarg.0
  IL_0030:  ldc.i4.0
  IL_0031:  call       instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
  IL_0036:  stloc.2
  IL_0037:  ldloc.0
  IL_0038:  ldc.i4.1
  IL_0039:  sub
  IL_003a:  stloc.3
  IL_003b:  ldarg.0
  IL_003c:  ldc.i4.1
  IL_003d:  ldloc.3
  IL_003e:  call       instance class [mscorlib]System.Collections.Generic.List`1<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetRange(int32,
                                                                                                                                                         int32)
  IL_0043:  stloc      V_4
  IL_0047:  nop
  IL_0048:  nop
  IL_0049:  ldloc.2
  IL_004a:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_004f:  ldloc      V_4
  IL_0053:  nop
  IL_0054:  nop
  IL_0055:  call       void switch.show(class [mscorlib]System.Collections.Generic.List`1<int32>)
  IL_005a:  br         IL_005f

  IL_005f:  ret
} // end of global method switch.show

.NETのYieldが何をしているか

.NETのYieldがどんなふうにILを出力してるんか調べてみた
VBだけ調べたけどC#も多分一緒だろう
割とcall/ccするのめんどいな

1. Yieldの付いた関数毎にIEnumeratorなクラスを作る、とりあえずStateMachineと呼ぶ
2. Yieldの付いた関数の引数、ローカル変数を全部メンバ変数に持つ
3. 戻り値と状態もメンバ変数に持つ
4. Yieldの出現箇所にユニークな連番を振る
5. Yieldしている個所の前で次のことをする
・Yieldの値を戻り値のメンバ変数に入れる
・4.で付けたユニークな番号を状態のメンバ変数に入れる
・Return Trueしとく
・Returnの後にユニークな番号に対応したラベルを張る
6. 関数を抜けるときに次のことをする
・最終行でっせというラベルを張る
・状態のメンバ変数に最終行でっせという値を入れる
・Return Falseする

' 呼び出し側
For Each x In Cdr(xs)
    ' なんか処理
Next

Public Shared Iterator Function Cdr(xs As List(Of Integer))
	For i = 1 To xs.Count - 1
		Yield xs(i)
	Next
End Function' 呼び出し側
For Each x In New StateMachine With {._xs = xs}
    ' なんか処理
Next

' Yieldの関数展開結果
Class StateMachine
	Implements IEnumerator

	Private _i As Integer
	Private _xs As List(Of Integer)
	
	Private _value As Integer
	Private _state_machine As Integer = 0
	
	Public ReadOnly Property Current() As Boolean
		Get
			Return _value
		End Get
	End Property
	
	Public Function MoveNext() As Boolean
		
		If _state_machine = 1 Then Goto __STATE1
		If _state_machine = 2 Then Goto __STATE2
		
		_i = 1
		Do While _i <= _xs.Count - 1
			
			_value = _xs(_i)
			_state_machine = 1
			Return True
			__STATE1:
			
			_i += 1
		Loop
		
		__STATE2:
		_state_machine = 2
		Return False
	End Function
End Class

簡単にcdrするILの関数書きたいだけなんだけど難しいなー・・・

クラッシュレポートを表示しない方法

Windowsでわざとクラッシュするプログラムを作ると報告ダイアログなんかがでてきてうっとうしかった
標準エラーにエラーはいてただ落ちればいいのに・・・


レジストリを設定すれば正しい動作に修正できるみたい
ついでにクラッシュダンプも作るのやめれるっぽい
これでセグメンテーションフォルト起こし放題だね!やったね!

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting]
"DisableQueue"=dword:00000001
"ForceQueue"=dword:00000001

関数の戻り値型から空配列の型解決

なんのこっちゃか分かりにくいけど
戻り値の型から空配列の型解決ができるようになった
f:id:zenu:20170913204222p:plain

型解決をするために配列を正規化している

return([])
↓
$0 = []
return($0)

これをやると問題になるのがこんなやつ

xs = [Int]()
↓
$0 = [Int]
xs = $0()

Intってのが型解決してみるまで変数なのか型なのか分からないので$0が配列型か配列か分からない
ってゆーか、変数に型の代入ができなかった


Nodeにインスタンスか型なのかのフラグを付けて対応したけど、これができひんのは分かっている
どうしようもないので後で考える

var xs = []
xs.Add(Int)
var i = xs[0]()

ブラックジャックの点数

ブラックジャックの点数を数えるプログラムが思ってたのと全然違った
employment.en-japan.com

Aを2回以上11と数えるとバースト確実やねんから
Aの枚数=Aの合計値とみなしてかまへん

Aの枚数とA以外の合計値を求め、合計値-1が10以下ならA1枚を11とする
他はAを1と数えるだけでいい

せやないと6個のデッキをごちゃまぜにしてプレイしたときの
エース21枚という合法手に対し計算がややこしくなるやん(するかい、そんなん)

sumHand2 :: [Card] -> Int
sumHand2 cards | as == 0           = ax
               | ax + as - 1 <= 10 = ax + as - 1 + 11
               | otherwise         = ax + as
               where (a, xs) = partition (== A) cards
                     ax      = sum (map toPoint2 xs)
                     as      = length a

toPoint2 :: Card -> Int
toPoint2 A     = 1 -- 不要だけど書いておく
toPoint2 (N n) = n
toPoint2 _     = 10

そういえば練習でポーカーの手役を判定するプログラムと麻雀のシャンテン数を数えてたけど
作り途中でほっぽったのはどこ行ったんだろう
前のPCの中かな?