Easy AtCoder
Mix.install(
[
{:httpoison, "~> 2.2.1"},
{:floki, "~> 0.35.2"},
{:kino, "~> 0.12.0"},
{:mock, "~> 0.3.8"}
],
config: [my_app: [use_myio: true]]
)
modules
defmodule AtCoder do
import Mock
defstruct [:contest_name, :problem_name, :samples_in, :samples_out]
def new(contest_name, problem_name) do
url =
"https://atcoder.jp/contests/#{contest_name}/tasks/#{contest_name}_#{problem_name}"
doc = HTTPoison.get!(url)
{:ok, html} = Floki.parse_document(doc.body)
section_list = Floki.find(html, "section")
samples_in =
section_list
|> Enum.filter(fn {_, _, [hd | _]} -> String.starts_with?(Floki.text(hd), "入力例") end)
|> Enum.map(fn {_, _, [_hd | tail]} -> Floki.text(hd(tail)) end)
|> Enum.map(fn x -> String.replace(x, "\r\n", "\n") end)
samples_out =
section_list
|> Enum.filter(fn {_, _, [hd | _]} -> String.starts_with?(Floki.text(hd), "出力例") end)
|> Enum.map(fn {_, _, [_hd | tail]} -> Floki.text(hd(tail)) end)
|> Enum.map(fn x -> String.replace(x, "\r\n", "\n") end)
struct!(%AtCoder{},
contest_name: contest_name,
problem_name: problem_name,
samples_in: samples_in,
samples_out: samples_out
)
end
def run_main(string_in) do
{:ok, file} = StringIO.open(string_in)
with_mock IO, [:passthrough],
getn: fn :stdio, a, b -> passthrough([file, a, b]) end,
getn: fn a, b -> passthrough([file, a, b]) end,
read: fn :stdio, option -> passthrough([file, option]) end,
read: fn option -> passthrough([file, option]) end,
puts: fn :stdio, item -> passthrough([file, item]) end,
puts: fn item -> passthrough([file, item]) end do
Main.main()
end
{:ok, {_, result}} = StringIO.close(file)
result
end
def judge(string_in, string_out) do
result = run_main(string_in)
if string_out == result do
IO.puts("OK")
true
else
IO.inspect(string_in, label: "Input")
IO.inspect(string_out, label: "Expected")
IO.inspect(result, label: "Received")
false
end
end
def judge_all(%AtCoder{samples_in: samples_in, samples_out: samples_out}) do
n =
for {{sample_in, sample_out}, n} <- Enum.zip([samples_in, samples_out]) |> Enum.with_index() do
IO.puts("-- TEST #{n} --")
AtCoder.judge(sample_in, sample_out)
end
|> Enum.count()
IO.puts("Passed #{n} of #{length(samples_in)}")
end
end
contest_name = Kino.Input.text("コンテスト名")
problem_name = Kino.Input.text("問題名")
judge_all = Kino.Control.button("入力例で実行")
Kino.listen(judge_all, fn _event ->
atcoder = AtCoder.new(Kino.Input.read(contest_name), Kino.Input.read(problem_name))
AtCoder.judge_all(atcoder)
end)
input_string = Kino.Input.textarea("入力")
run = Kino.Control.button("実行")
Kino.listen(run, fn _event ->
input_string
|> Kino.Input.read()
|> AtCoder.run_main()
|> IO.puts()
end)
frame = Kino.Frame.new()
Kino.Frame.render(
frame,
Kino.Layout.grid(
[
Kino.Layout.grid([contest_name, problem_name, judge_all], columns: 1),
Kino.Layout.grid([input_string, run], columns: 1)
],
columns: 2
)
)
回答
defmodule Main do
def next_token(acc \\ "") do
case IO.getn(:stdio, "", 1) do
" " -> acc
"\n" -> acc
x -> next_token(acc <> x)
end
end
def input(), do: IO.read(:line) |> String.trim()
def ii(), do: next_token() |> String.to_integer()
def li(), do: input() |> String.split(" ") |> Enum.map(&String.to_integer/1)
def main() do
x = input()
IO.puts(x)
end
end
実行
frame