paiza.ioでelixir その200

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
俺cpuのアセンブラを実行する、インタープリタで九九を実行せよ。

# サンプルコード

```
defmodule Va do
	use Agent
	def start_link() do
		Agent.start_link(fn ->
			0
		end, name: __MODULE__)
	end
	def get() do
		Agent.get(__MODULE__, fn v ->
			v
		end)
	end
	def set(x) do
		Agent.update(__MODULE__, fn v ->
			x
		end)
	end
end
defmodule Src do
	use Agent
	def start_link() do
		Agent.start_link(fn -> 
            ""
		end, name: __MODULE__)
	end
	def set(x) do
		Agent.update(__MODULE__, fn v ->
	        x
		end)
	end
	def get() do
		Agent.get(__MODULE__, fn v ->
			v
		end)
	end
	def getn(n) do
		Agent.get(__MODULE__, fn v ->
	    	Enum.at(String.split(v, "\n", trim: true), n - 1)
	    end)
    end
    def getl("end") do
        0
    end
	def getl(a) do
		Agent.get(__MODULE__, fn v ->
            Enum.reduce(String.split(v, "\n", trim: true), 1, fn l, n ->
	    	    if String.starts_with?(l, a) do
	    	        Va.set(n)
	    	    end
	    	    n = n + 1
	        end)
	        Va.get
	    end)
    end
end
defmodule Sim do
    def val(s) do
        if String.starts_with?(s, "'") do
            String.at(s, 1)
            |> String.to_charlist
            |> List.first
        else
            String.to_integer(s)
        end
    end
	def start_link do
		Agent.start_link(fn ->
			[a: 0, b: 0, c: 0, pc: 1, stack: [], g: ""]
		end, name: __MODULE__)
	end
	def push(s) do
		Agent.update(__MODULE__, fn v ->
    	    n = val(s)
		    stack = v[:stack]
			stack = Enum.concat(stack, [n])
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
	end
    def set(d) do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
		    stack = Enum.drop(stack, -1) 
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			cond do
			d == "a" ->
    			v = List.keyreplace(v, :a, 0, {:a, top})
	    		pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
			d == "b" ->
    			v = List.keyreplace(v, :b, 0, {:b, top})
	    		pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
			d == "c" ->
    			v = List.keyreplace(v, :c, 0, {:c, top})
	    		pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
			end
		end)
    end
    def get(d) do
		Agent.update(__MODULE__, fn v ->
		    cond do
		    d == "a" ->
    		    a = v[:a]
	    	    stack = v[:stack]
		        stack = Enum.concat(stack, [a])
			    v = List.keyreplace(v, :stack, 0, {:stack, stack})
		      	pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
		    d == "b" ->
    		    b = v[:b]
	    	    stack = v[:stack]
		        stack = Enum.concat(stack, [b])
			    v = List.keyreplace(v, :stack, 0, {:stack, stack})
		      	pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
		    d == "c" ->
    		    c = v[:c]
	    	    stack = v[:stack]
		        stack = Enum.concat(stack, [c])
			    v = List.keyreplace(v, :stack, 0, {:stack, stack})
		      	pc = v[:pc] + 1
		    	List.keyreplace(v, :pc, 0, {:pc, pc})
			end
		end)
    end
    def rnd() do
		Agent.update(__MODULE__, fn v ->
		    rnd = Enum.random(0..255)
		    stack = v[:stack]
		    stack = Enum.concat(stack, [rnd])
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def gt() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
			po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			tmp = Enum.with_index(stack)
			po = po - 1
			stack = Enum.map(tmp, fn {val, ind} ->
				cond do
				ind == po ->
					val > top
				true ->
					val
				end
			end)
			stack = Enum.drop(stack, -1)
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def eq() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
			po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			tmp = Enum.with_index(stack)
			po = po - 1
			stack = Enum.map(tmp, fn {val, ind} ->
				cond do
				ind == po ->
					val == top
				true ->
					val
				end
			end)
			stack = Enum.drop(stack, -1)
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def if_(t) do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
		    stack = Enum.drop(stack, -1) 
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			if top do
			    pc = Src.getl(t)
	    		List.keyreplace(v, :pc, 0, {:pc, pc})
			else
			    pc = v[:pc] + 1
	    		List.keyreplace(v, :pc, 0, {:pc, pc})
			end
		end)
    end
    def jmp(t) do
		Agent.update(__MODULE__, fn v ->
		    pc = Src.getl(t)
    		List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
	end
    def out3() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    g = v[:g]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
		    o = Integer.floor_div(top, 100)
		    g = g <> to_string(o)
            v = List.keyreplace(v, :g, 0, {:g, g})
		    pc = v[:pc] + 1
		    List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
	def out2() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    g = v[:g]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			o = rem(top, 100)
		    o = Integer.floor_div(o, 10)
		    g = g <> to_string(o)
            v = List.keyreplace(v, :g, 0, {:g, g})
		    pc = v[:pc] + 1
		    List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def out1() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    g = v[:g]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
		    o = rem(top, 10)
		    g = g <> to_string(o)
            v = List.keyreplace(v, :g, 0, {:g, g})
		    pc = v[:pc] + 1
		    List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def drop() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    stack = Enum.drop(stack, -1) 
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
		    pc = v[:pc] + 1
		    List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def out() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
		    g = v[:g]
		    po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
		    g = g <> <<top ::utf8>>
            v = List.keyreplace(v, :g, 0, {:g, g})
		    stack = Enum.drop(stack, -1) 
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
		    pc = v[:pc] + 1
		    List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def add() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
			po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			tmp = Enum.with_index(stack)
			po = po - 1
			stack = Enum.map(tmp, fn {val, ind} ->
				cond do
				ind == po ->
					val + top
				true ->
					val
				end
			end)
			stack = Enum.drop(stack, -1)
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def mul() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
			po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			tmp = Enum.with_index(stack)
			po = po - 1
			stack = Enum.map(tmp, fn {val, ind} ->
				cond do
				ind == po ->
					val * top
				true ->
					val
				end
			end)
			stack = Enum.drop(stack, -1)
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
    def rem() do
		Agent.update(__MODULE__, fn v ->
		    stack = v[:stack]
			po = Enum.count(stack) - 1
			top = Enum.at(stack, po)
			tmp = Enum.with_index(stack)
			po = po - 1
			stack = Enum.map(tmp, fn {val, ind} ->
				cond do
				ind == po ->
					rem(val, top)
				true ->
					val
				end
			end)
			stack = Enum.drop(stack, -1)
			v = List.keyreplace(v, :stack, 0, {:stack, stack})
			pc = v[:pc] + 1
			List.keyreplace(v, :pc, 0, {:pc, pc})
		end)
    end
	def print() do
		Agent.get(__MODULE__, fn v ->
            g = v[:g]
            IO.puts g
        end)
    end
	def pc() do
		Agent.get(__MODULE__, fn v ->
            v[:pc]
        end)
    end
    def test() do
		Agent.get(__MODULE__, fn v ->
            v
        end)
    end
end

defmodule Main do
    def run(0) do
        Sim.print()
    end
    def run(pc) do
        m = Src.getn(pc)
        #IO.puts(m)
        s = String.split(m, "  ")
        cond do
	    Enum.at(s, 1) == "set" ->
    	    Sim.set(Enum.at(s, 2))
	    Enum.at(s, 1) == "get" ->
	   	    Sim.get(Enum.at(s, 2))
	    Enum.at(s, 1) == "rnd" ->
	   	    Sim.rnd()
	    Enum.at(s, 1) == ">" ->
		    Sim.gt()
	    Enum.at(s, 1) == "=" ->
		    Sim.eq()
	    Enum.at(s, 1) == "if" ->
		    Sim.if_(Enum.at(s, 2))
	    Enum.at(s, 1) == "out3" ->
		    Sim.out3()
	    Enum.at(s, 1) == "out2" ->
		    Sim.out2()
	    Enum.at(s, 1) == "out1" ->
		    Sim.out1()
	    Enum.at(s, 1) == "drop" ->
		    Sim.drop()
	    Enum.at(s, 1) == "out" ->
		    Sim.out()
	    Enum.at(s, 1) == "+" ->
		    Sim.add()
	    Enum.at(s, 1) == "%" ->
		    Sim.rem()
	    Enum.at(s, 1) == "*" ->
		    Sim.mul()
   	    Enum.at(s, 1) == "jmp" ->
		    Sim.jmp(Enum.at(s, 2))
	    true ->
		    Sim.push(Enum.at(s, 1))
	    end
	    #IO.inspect Sim.test
        run(Sim.pc)
	end
	def start(str) do
	    Src.set(str)
	    run(1)
	end
end
Va.start_link
Sim.start_link
Src.start_link

str = """
  1
  set  a
  1
  set  b
loop  get  a
  get  b
  *
  out3
  out2
  out1
  drop
  ' '
  out
  get  a
  1
  +
  set  a
  10
  get  a
  >
  if  loop
  10
  out
  get  b
  1
  +
  set  b
  1
  set  a
  10
  get  b
  >
  if  loop
  jmp  end
"""
Main.start(str)

```

# 実行結果

```
001 002 003 004 005 006 007 008 009 
002 004 006 008 010 012 014 016 018 
003 006 009 012 015 018 021 024 027 
004 008 012 016 020 024 028 032 036 
005 010 015 020 025 030 035 040 045 
006 012 018 024 030 036 042 048 054 
007 014 021 028 035 042 049 056 063 
008 016 024 032 040 048 056 064 072 
009 018 027 036 045 054 063 072 081 

```

# 成果物

https://paiza.io/projects/U9RuWaBd51Bf8dcLOQWeUw?language=elixir


以上。