Kuin Advent Calendar 2016 - 22日目

この記事は【Kuin Advent Calendar 2016】の22日目の記事です。

←前の日の記事   →次の日の記事

【記事中で紹介しているコードについて】
コンパイルが通らない場合など、不具合があれば、@tatt61880まで連絡いただけると助かります。よろしくお願いいたします。


Befungeのコードを実行するKuinのコードです。
befunge.kn
{難解プログラミング言語「Befunge」のコードを実行します。}
func main()
	{Hello, world!を出力します。Wikipediaに掲載されていたBefungeのコードです。}
	do @befunge(["v @_       v",
				|">0\"!dlrow\"v",
				|"v  :#     <",
				|">\" ,olleH\" v",
				|"   ^       <"])

	{7の階乗の値を出力します。Wikipediaに掲載されていたBefungeのコードです。}
	do @befunge(["7 100p:v",
				|"v *g00:_00g.@",
				|">00p1-:^"])

	{
	TokusiNさんのHello, world!です。(1つ目)
	http://golf.shinh.org/reveal.rb?Hello+broken+keyboard/TokusiN_1370797591&bef
	読みやすさのために行を分けていますが、1行の文字列です。
	}
	do @befunge(["!:::::++:++:+:++:++:+::!:p::!!:p::!!:+:p::!!::++:p:!!:+:+:p!::+:++::++:+:+::!:!p" ~
				|"!!!::+:+:!!:+++:+:+:+:+::!!:p++:+::!:!::++:!!:p+!!::++::!!::p+!!::+:!!::p+::!!::" ~
				|"!!!:++:::++:+:+:+:+::!p++:!!::++::!!:+++:+:+::!!:p+!!:+::+:!!::++:++:+:+:+:::!p+" ~
				|"!!!!++::!!::+:+:+:+:+:!!:++:+:+:!!::++::++:+:++:+:+:::!!:++:++::!!::++:+:+:!!::+" ~
				|":+:!!!::+:+::!!:++:+:++:+:+:++::::!!::++::+:+:++:+:+::!!:++::++:+:++:+:+:::!!:++" ~
				|"!::!!++:+:+:+:!!:+:+:+:+:+:+:!!::+:++:p"
				|])

	{
	TokusiNさんのHello, world!です。(2つ目)
	http://golf.shinh.org/reveal.rb?Hello+broken+keyboard/TokusiN(AllAscii)_1370537872&bef
	}
	do @befunge(["\"v1AQ$(.TD4/02\\L<3uwt{}789prs:;=xyz?BC!%&EFJ*)'KMNijdOPRnoqSUVkmlWXYf56Z[]GIH^`a",
				|"b> #,+-_@cegh|~"])
end func

func befunge(src_: [][]char)
	class Vec()
		+var x: int
		+var y: int
		+func init(x: int, y: int): Vec
			do me.x :: x
			do me.y :: y
			ret me
		end func
	end class
	func normalize(src: [][]char): [][]char
		var res: [][]char :: #[25][]char
		for i(0, 24)
			do res[i] :: "                                                                                "
		end for
		var w: int :: 0
		var h: int :: 0
		for i(0, ^src - 1)
			for j(0, ^src[i] - 1)
				if(w = 80)
					do w :: 0
					do h :+ 1
				end if
				do res[h][w] :: src[i][j]
				do w :+ 1
			end for
			do w :: 0
			do h :+ 1
		end for
		ret res
	end func
	var src: [][]char :: normalize(src_)
	var w: int :: ^src[0]
	var h: int :: ^src
	{
	do cui@print("==================================================================================\n")
	for i(0, ^src - 1)
		do cui@print("[\{src[i]}]\n")
	end for
	do cui@print("==================================================================================\n")
	}
	var p: Vec :: (#Vec).init(0, 0)
	var d: Vec :: (#Vec).init(1, 0)
	var st: MyIntStack :: #MyIntStack
	class MyIntStack() {スタックが空の時にpopされると0を返すようなスタックです。}
		var s: stack<int>
		*func ctor()
			do me.s :: #stack<int>
		end func
		+func pop(): int
			if(^me.s = 0)
				ret 0 {スタックが空なので0を返します。}
			else
				ret me.s.get()
			end if
		end func
		+func push(v: int)
			do me.s.add(v)
		end func
	end class

	var max_count: int :: 10000
	var count: int :: 0
	var xxx: bool :: false
	var strFlag: bool :: false
	while a(true)
		do count :+ 1
		do p.x :: (p.x + w) % w
		do p.y :: (p.y + h) % h
		if(count = max_count)
			do cui@print("\n無限ループ回避のために、繰返し回数を" ~ max_count.toStr() ~ "回までに制限しています。\n")
			ret
		end if

		if(xxx)
			do xxx :: false
		elif(strFlag)
			if(src[p.y][p.x] = '"')
				do strFlag :: false
			else
				do st.push(src[p.y][p.x] $ int)
			end if
		else
			var x: int
			var y: int
			switch c(src[p.y][p.x])
			{制御}
			case '<'
				do d :: (#Vec).init(-1,  0)
			case '>'
				do d :: (#Vec).init( 1,  0)
			case '^'
				do d :: (#Vec).init( 0, -1)
			case 'v'
				do d :: (#Vec).init( 0,  1)
			case '_'
				do d :: (#Vec).init((st.pop() = 0) ?(1, -1), 0)
			case '|'
				do d :: (#Vec).init(0, (st.pop() = 0) ?(1, -1))
			case '?'
				switch(lib@rnd(0, 3))
				case 0
					do d :: (#Vec).init(-1,  0)
				case 1
					do d :: (#Vec).init( 1,  0)
				case 2
					do d :: (#Vec).init( 0, -1)
				case 3
					do d :: (#Vec).init( 0,  1)
				end switch
				assert false
			case ' '
			case '#'
				do xxx :: true
			case '@'
				do cui@print("\n")
				ret
			{リテラル}
			case '0' to '9'
				do st.push(c $ int - '0' $ int)
			case '"'
				do strFlag :: true
			{入出力}
			case '&'
				{FIXME}
				do cui@print("未実装です。(&)")
				assert false
			case '~'
				{FIXME}
				do cui@print("未実装です。(~)")
				assert false
			case '.'
				do cui@print(st.pop().toStr() ~ " ")
			case ','
				do cui@print([st.pop() $ char])
			{算術および論理演算}
			case '+'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(x + y)
			case '-'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(x - y)
			case '*'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(x * y)
			case '/'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(x / y)
			case '%'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(x % y)
			case '`'
				do y :: st.pop()
				do x :: st.pop()
				do st.push((x > y) ?(1, 0))
			case '!'
				do st.push(st.pop() = 0 ?(1, 0))
			{スタック操作}
			case ':'
				var s: int :: st.pop()
				do st.push(s)
				do st.push(s)
			case '\\'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(y)
				do st.push(x)
			case '$'
				do st.pop()
			{メモリ操作}
			case 'g'
				do y :: st.pop()
				do x :: st.pop()
				do st.push(src[y][x] $ int)
			case 'p'
				do y :: st.pop()
				do x :: st.pop()
				var v: int :: st.pop()
				do src[y][x] :: v $ char
			default
				do cui@print("予期せぬ文字です。")
				assert false
			end switch
		end if
		do p.x :: (p.x + d.x + w) % w
		do p.y :: (p.y + d.y + h) % h
	end while
end func

出力結果
Hello, world!
5040
Hello, world!
Hello, world!

←前の日の記事   →次の日の記事