NixOSでroswell経由でQlotを使う方法

まとめ

Qlotを使用したいなら、roswellはこちらを参考に手動ビルドしたものを使うと良いです。

原因

NixOSでroswellを入れてqlot installをすると、謎のエラーとともに終了します。 これの理由としてNixで入るroswellとQlotが背景で行っている処理が関係します。

Nixで入るroswellについて

Nix経由で入れたroswellは一部の引数が正しく動作しないようです。その一つとして+Qフラグがあります。+Qフラグを用いるとquicklispなしで処理系が立ち上がるのですが、なぜかNixで入れたroswellだとそうなりません。

# quickloadがなぜか動く
ros run +Q -e '(ql:quickload :qlot)'

Qlotが背景ですることについて

qlot installを実行したときに最初の方で行う処理として、新しいプロジェクト用のquicklispのインストールがあります。 quicklispのインストールでは、インストールスクリプトをシェルコマンド経由で実行します。 このスクリプトは、+Qフラグを渡してroswellに渡してquicklispを除いた処理系の上で実行されます。 これは、quicklispのインストールスクリプトを実行したときに、すでに環境にquicklispが入っているとインストールを中断するためです。

結論

Qlotは処理中でquicklispをインストールします。 quicklispのインストールはすでに環境にquicklispが入っているとインストールが中断されるため、+Qフラグを渡したroswellで実行しています。 しかし、Nixで入ったroswellは+Qフラグを正しく処理しないために、quicklispのインストールが中断されるわけです。

上の原因により、Nix以外の方法でroswellは導入する必要があります。 幸いにroswellの公式がNixOS向けのインストール手順を公開しているのでそちらを利用しましょうインストール手順へのリンク

Windowsでi3wmを使う方法

Windowsでi3wmを使う方法

こんにちはEnderedです。

2022/11/20に行われた部内LTで発表した内容がそこそこ有益だと思うので残します。

スライドはこちらです。

i3wmの使い方

ここ数年で発展してきたWSLのなかでも、WSLgと呼ばれるものを用いてi3wmを描画します。おそらくWSL2でしか動作しないのでWSL1を使っている人は頑張ってください。

事前に必要なもの

ここではUbuntuでのインストールコマンドだけ併記しておきます。(他のOSをWSLで使う人は問題ないと思うので)

  • Xwayland
    • apt install xwayland
  • i3wm
    • apt install i3

起動の仕方

Xwayland :1 &

WAYLAND_DISPLAY= DISPLAY=:1 i3

1つ目のコマンドと2つ目のコマンドで時間差を置かないとうまく起動しなかったので、スクリプトを書くときは注意してください。

特徴

  • マルチディスプレイに勝手に対応してくれるのでとても便利

想定される問題

WindowsキーWindows側に吸われる

キーのリマップをしましょう。Microsoft StoreからPowerToysをインストールして、Windowsキーを好きなキーに置き換えます。Linux側でキーバインドをいじれば普段の環境で作業できると思います。(Windows側の環境が壊れますが、i3wmがあるならわざわざWindows側を操作する必要はないので…)

PowerToysだとWindowsキーが絡んだ複合キーのリマップがうまく行かないのですが(Win+wなど)対処法がまだわかっていません。

dmenuの初回起動がとても遅い

どうにかしたいんですが、PATHを上書きする等しないと無理そうです。

他あったら追記します

感想

今までMacOSで仕事してきましたが、ここまでできるならWindowsで良いかなと思いました。

LINEでオウム返しボットを作ってみました(LISP)

こんにちは

この記事は、Aizu Advent Calendar 2021の21日目の記事です。 (遅刻したけど許して…)

LINEでオウム返しボットを作りました

どうもこんばんは,Enderedです。今回Advent CalendarということでLINEのオウム返しボットを作りました。

開発環境

  • サーバ
    • Vultr(VPSって安いですね)
  • 言語
  • ライブラリ
    • clack (サーバ要因1)
    • ningle (サーバ要因2)
    • cl-json
    • dexador (LINEAPIにデータを送るため)
  • その他
    • nginx (HTTPS通信のため)

実装

localhost/parrot以下にLINE用のAPIをはやします。

(defpackage :parrot.view
  (:use :cl :parrot.util)
  (:export
   :*app*))
(in-package :parrot.view)

(defvar *app* (make-instance 'ningle:<app>))

(setf (ningle:route *app* "/parrot" :method :POST)
      (lambda (params)
    (parrot.util:with-protect-to-json
      (let* ((events (car (parrot.util:access params "events")))
         (message (or (parrot.util:access events "message" "text") "NO MESSAGE"))
         (reply-token (or (parrot.util:access events "replyToken") "INVALID")))
        (dexador:post
         parrot.config:*post-url*
         :headers `(("Content-Type" . "application/json")
            ("Authorization" . ,(format nil "Bearer ~a" parrot.config:*access-token*)))
         :content (json:encode-json-to-string
               (list
            (cons "replyToken" reply-token)
            (cons "messages"
                  `((("type" . "text")
                 ("text" . ,message))))))))
      '(("status" . "OK")))))
(defpackage :parrot.util
  (:use :cl)
  (:export
   :parse-number
   :with-protect-to-json
   :access))

(in-package :parrot.util)

(defun access (data &rest path)
  (reduce (lambda (data path)
        (cdr (assoc path data :test #'equal)))
      (cons data path)))

(defmacro with-protect-to-json (&body body)
  `(handler-case
       `(200 (:content-type "application/json")
             (,(json:encode-json-to-string (progn ,@body))))
     (error (e)
       `(500 (:content-type "application/json")
             (,(json:encode-json-to-string
        `((:|error| . ,(format nil "~A" e)))))))))

JS関連の実装例を読んでいるとfetch関数にpayloadというフィールドを含んだデータを渡しているので,なんだろうと思ってたらcontentのことでした(ここで2時間くらい止まりました)。

おまけ

文字列をただ受け取ってただ返すだけのプログラムを書くのは退屈ではありませんか?(そうでない人は精神が強いです)。なので,S式を受け取ったら評価した結果を返すプログラムを書きましょう。

仕様

トークナイザの実装と内部表現に変換するために,受け取るS式の仕様を考えます。今回は簡単なS式を評価したいだけなので,括弧がS式の開始と終了でそれ以外はシンボルとして扱います。

トークナイザ

先程の仕様から,トークナイザを実装します。リーダマクロ等がないのでここは簡単です。

(defun inject-space (str)
  (map 'string
       #'identity
       (loop for ch across str
         if (or (eq ch #\() (eq ch #\)))
           append (list #\space ch #\space)
         else
           append (list ch))))

(defun split (str del)
  (let ((pos (search del str :test #'equal)))
    (if pos
    (cons (subseq str 0 pos)
          (split (subseq str (+ pos (length del))) del))
    (list str))))

(defun split-by-space (str)
  (remove "" (split (map 'string (lambda (v) (if (or (eq v #\tab) (eq v #\newline)) #\space v)) str) " ") :test #'equal))

(defun split-s-expression (str) ;; トークナイザのトップレベル
  (split-by-space (inject-space str)))

括弧の前後にスペースを注入して,その後にスペースがある位置で文字列を分割・邪魔なデータを取り除くだけです。

内部表現への変換

トークナイザ後のデータからS式を構築します。S式を次のようなBNFで定義します。

TOP ::= VALUE | PAREN
VALUE ::= 括弧以外の文字列
PAREN ::= "(" {TOP} ")"

S式は単純でいいですね,それでは書いていきます。

(defun parse-s-expression (str)
  (labels ((top (lst) 
         (let ((v (paren lst))) (when v (return-from top v)))
         (let ((v (value lst))) (when v (return-from top v))))
       (value (lst)
         (if (or (null lst) (equal "(" (car lst)) (equal ")" (car lst)))
         nil
         lst))
       (paren (lst)
         (unless (equal (car lst) "(") (return-from paren nil))
         (labels ((rec (lst)
            (let ((v (top lst)))
              (cond (v
                 (let ((v2 (rec (cdr v))))
                   (when v2
                     (cons (cons (car v) (car v2)) (cdr v2)))))
                (t
                 (when (equal (car lst) ")")
                   (cons nil (cdr lst))))))))
           (rec (cdr lst)))))
    (let ((res (top (split-s-expression str))))
      (and res (not (cdr res)) (car res)))))

eval

あとは自作Lispに好きな関数/マクロ定義を追加するだけですね。

(defun line-eval (str)
  (labels ((rec (lst values)
         (format t "~a:~a~%" lst values)
         (unless lst
           (return-from rec nil))
         (when (stringp lst)
           (return-from rec
         (cond ((parse-integer lst :junk-allowed t) (parse-integer lst :junk-allowed t))
               (t (cdr (assoc lst values :test #'equal))))))
         (let ((op (car lst)))
           (cond ((equal op "if") (if (print (rec (nth 1 lst) values)) (rec (nth 2 lst) values) (rec (nth 3 lst) values)))
             ((equal op "<") (apply #'< (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op ">") (apply #'> (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op "<=") (apply #'<= (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op ">=") (apply #'>= (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op "=") (apply #'= (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op "/=") (apply #'/= (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
             ((equal op "lambda")  (lambda (args)
                         (let ((values (append (mapcar #'cons (second lst) args) values)))
                           (car (last (mapcar (lambda (body) (rec body values)) (cddr lst)))))))
             ((equal op "labels") 
              (let ((next-values (append (mapcar (lambda (func)
                              (cons (car func)
                                nil))
                            (cadr lst))
                        values)))
            (mapc (lambda (func) (setf (cdr (assoc (car func) next-values :test #'equal))
                           (rec `("lambda" ,@ (cdr func)) next-values)))
                  (cadr lst))
            (car (last (mapcar (lambda (body) (rec body next-values)) (cddr lst))))))
             (t
              (let ((args (mapcar (lambda (arg) (rec arg values)) (cdr lst))))
            (funcall (cdr (assoc op values :test #'equal)) args)))))))
    (handler-case
    (format nil "~a" (rec
              (parse-s-expression str)
              (list (cons "+" (lambda (args) (apply #'+ args)))
                (cons "-" (lambda (args) (apply #'- args)))
                (cons "*" (lambda (args) (apply #'* args)))
                (cons "/" (lambda (args) (apply #'/ args)))
                (cons "funcall" (lambda (args) (funcall (car args) (cdr args)))))))
      (error (e)
    (declare (ignore e))
    "ERROR"))))

上記を実行した結果

とりあえずで語尾に"天才ですから"を追加しましたが,軽く後悔しています。

感想

LINEでオウム返しボットを作るのは楽しいですね。

zoomにカメラがないPCで接続してしまったときの対処方(カメラ付きLinux機を持ってる場合)

動機(特に重要な内容ではない)

今回,私は喜ばしいことにインターンに行くことが出来ました。この日のために,前日からデスクトップPCを購入し(メイン機が低スペックすぎたので)マイク付きイヤホンを2度購入し(1つめはドライバが非対応でした)万全の状態で望んだわけですが,当日に重大な問題が発生しました。デスクトップにはカメラが内蔵されていないのです(忘れてました)。自己紹介で顔を見せれないというイベントに冷や汗をかきながら,手元のLinux機(内蔵カメラ付きノートPC)でどうにか出来ないかと調べたらなんとか出来たので,忘れないうちにメモしておこうというのが今回の投稿です。

本編

注意

私は今回使った技術に詳しくないので,環境が違うと動作しないかもしれません。

私の構成

  • Windows10(Aと呼ぶ)
    • Zoomが動作しているPC
    • OBSが必要(v26以降)
  • Ubuntu20.04(Bと呼ぶ)
    • カメラが内蔵されているPC
    • ffmpegが必要

方法

B側で以下のコマンドを実行します。中括弧内{}は適宜適した値を入れてください

ffmpeg \
    -i /dev/{B側の利用したいカメラ} \
    -vcodec libx264 \
    -preset ultrafast \
    -tune zerolatency \
    -f mpegts \
    udp://{AのIPアドレス}:{適当な整数(今回は12321としました)}?pkg_size=1316

A側ではOBSを以下の順序で設定します。

  1. 左下のソースの下の方にある+を押して,メディアソースを選択。名前は適当に書いて新規作成します。
  2. {手順1.で入力した名前}のプロパティという画面が立ち上がるのでローカルファイルのチェックを外します。
  3. 新しく出てきた入力の部分にudp://{AのIPアドレス}:{B側のffmpegを実行時に入力した整数}を入力します。

多分この時点でOBS側にB側の内蔵カメラの映像が出力されると思うので,右下の仮想カメラ開始を押します。そしたら,zoomやdiscordなど,適当なアプリケーションで使えると思います。

感想

そこそこの遅延があると思うので,笑顔で誤魔化しましょう。

参考

競プロの個人的な始め方

注意

この文書は、競プロの環境構築やコーディング方法について説明する際に、口頭での説明よりも効率が良いであろうと思い、書かれた文書です。急ぎで書いたものなので、文章の雑さ等が有ります。筆者の主観的な理解を元に書かれるので、内容の誤り等はご容赦ください。また、必要と思った部分を加筆していく形式、を考えているので大幅な改変等あると思います。

この文書の内容

筆者が情報系の分野で一番悩むことは、「次に何を学べばよいのだろう」ということです。そのため、この文章の一番の目的は、読者に色々な物の名前を知ってもらうことです。殆どの場面で内容を深堀しません。ただ、文章に出てくる単語を検索すると、欲しい情報が簡単に出てくるはずです。

OS選択

以前に比べ、WSLが出てきたおかげでWindowsでも競プロが楽になりましたが、高度なことをするとWSL独自の設定が必要とされて、それの対応に時間と知識を必要とします。WSLの設定を行える自信が無い方はubuntuを入れて競プロをするのをおすすめします。macは利用をやめたのでわかりません。

Windows

Windowsで競プロをする方法は大まかに2つに分けられます。

  • VSCodeを用いてコーディング
  • WSLを用いてコーディング

1.については筆者があまり用いないので説明できません。そのため、2.についての説明を行います。

WSLの種類

WSLにはWSL1とWSL2と呼ばれる分類が有りますが、以下のような特徴があります。

  • WSL1: 環境構築が楽, 実行速度が遅い
  • WSL2: 環境構築が大変, 実行速度が早い

細かい部分が違いますが、競プロをする場合は上の認識でいいです。WSL1の実行速度が遅いというのは、本来の3,4倍位は実行時間が長いと考えていいです。WSL2は環境構築が大変ですが、実行速度が早いのでマラソン等を行うなら必須かと思います。ここでは、WSL1についてのみ説明します。

WSL1の環境構築

検索すれば情報が沢山出てくるので、その手続きに従ってubuntu環境のインストール及び実行確認をしてください(要加筆)。

次のソフトはWSLを用いる上で、よく使うのでインストールしておいたほうが良いです。

vcxsrv

X転送をWindows上で行うものですが、後述するGUIを用いるソフトはこれがないと動作しないので入れるほうが便利です。(後、大学の課題を家でできるようになります)

これ以降はubuntu上で行う設定と殆ど同じなのでubuntu編を参照してください。

ubuntu

これ以降はubuntu(もしくはWSL上のubuntu)で環境を構築する方法についてを説明していきます。

aptコマンド

とりあえずaptコマンドについて知りましょう。aptコマンドは、ソフトウェアをCUI環境でインストールするためのコマンドです。g++というソフトをインストールするときには次のようにします。

sudo apt update # sudo apt install をする前に必要とします。installできるソフトウェアについてなどの情報を得ます。
"パスワードを入力"
sudo apt install g++ # g++をインストール
"なにかしらの英文"(Y/n) # ここで (y or Y or 何も入力しない) + enterをすることによってインストールが出来ます

ここで先頭に来るsudoというのは、コマンドを偉い人視点で実行するために使うコマンドです。aptコマンドは使い方を間違えると大変なことになるので、sudoによって偉い人視点での許可を、普通は必要とします。sudoを用いて間違えたことをすると、簡単に環境が壊れるので使うときは慎重になりましょう。ここのg++という部分を好きなソフト名にすることによって必要なソフトをインストールしていきます。

エディタ

ここではvimemacsvscodeそれぞれについて説明します。 vimemacsは利点と欠点が逆の関係に近いので、両方を扱えることを個人的には推奨します。

vim

非常に単純な仕組み(浅い部分は)で操作できるので学習が容易です。とりあえず、初めて触るエディタとして選ぶのにいいと思います。

ubuntu環境だと標準で入っているので、ターミナルでvimと入力したら実行できると思います(終了する際には:qと入力してエンターを押してください)。操作方法はこれが非常に良い内容なので基本と初級編辺りを読んだらいいです。マニュアルを読む上で大事なのは、自分が使いたい内容を適宜学ぶことです。でないと、膨大な情報を解釈するのに多大な時間を費やしてプログラミングを開始できません。

vimを学ぶ上でいずれvimrcという存在に出会うことになると思います。ある意味、これがvimをエディタとして大成させた理由の大部分を占める、と言って過言ではないほど扱えた際の利点が多いです。私のvimrcを置いておくので、意味を学んで自分のvimrcに活かしてください。

emacs

自分でこのエディタを改造して行くつもりが無いならvimを学ぶことを推奨します。その程度に、このエディタの初期設定は貧弱だと思いますし、改造した際の便利さはvimを上回ると思います。実際、筆者は1年間vimで開発をしながらemacsについて勉強して、先月ほどからemacsをメイン開発環境に移行しました。

インストールは以下のコマンドで出来ます。

sudo apt update
sudo apt install emacs

ただ、ここでインストールされるのは最新版ではありません。

最新版には便利な機能もあるので、インストールしたい際はこの記事ubuntu欄のdockerファイルを読んでください。よく読むと、ターミナルに入力するコマンドと同じような書き方をされています。

vscode

情報がたくさんあり、操作も一番簡単です。ここではインストールする方法だけを説明します。ここの.debと書かれた部分をクリックすると、~~.debという名前のファイルがダウンロードされます。ダウンロードされたファイルをファイルソフト上でダブルクリックすると、インストールするための画面が出るのでinstallを押してください。

番外編(spacemacs)

spacemacsはemacsを土台として魔改造されたエディタです。非常に洗練された設定のもとで操作できるので、一度触ってみる価値が有ります。芸術品と思えるキーバインドでエディタを操作できるので、知識として触れておくべきです。

私のエディタの設定の殆どは、spacemacsの便利だと思った機能を再現する部分で構成されています。

プログラミング

これ以降は実際にプログラミングをする上で知っておくべきことを、筆者の独断と偏見を交えて説明していきます。

プログラミング言語

C++Pythonを基本的には競プロのために知っておくべきです。それぞれの特徴は以下のようになります。

  • C++: 実行速度が早い、標準で入っている機能が便利。
  • Python: 実行速度が遅い、大きな整数 (264 以上) を扱う際に便利。

このPythonの実行速度が遅いというのは、ICPCで使った際にTLEになることが普通というものです。例外として、実装が軽くて大きな整数を扱う、時にはPythonの独壇場になるので学んでいて損が無いです。

make

コンパイル言語で競プロをするなら使い方について知っておくべきです。Makefileという名前のファイルに以下のように書きます。

"好きな名前": "ソースコードのファイル名"
    "コンパイルするコマンド"

例えば、C++言語のmain.cppというソースコードg++コンパイルするには次のようになります。

a.out: main.cpp
  g++ main.cpp

その上でmakeとターミナルに入力するとコンパイルされます。makeコマンドは最後のコンパイルからファイルが編集されていないと、コンパイルされないので時間の節約になります。また、makeという短いコマンドで長いコマンドを指定することも可能なので、ストレス軽減に良いです。

サンプルを試す方法

プログラムを実行してサンプルを試す際、毎回コピー&ペーストをするのは何かと不便です。なので以下のようにして入力ファイルを作ります。

cat > 入力ファイル名 
"適当な入力"
"Ctrl + D"

こうして作成した入力ファイルを次のようにして試します。

./a.out < 入力ファイル名 #C++の場合
python3 main.py < 入力ファイル名 #Pythonの場合

サンプルを簡単に試せるというのは大事なことです。試すのが不便だと、サンプルを試さずに提出する、ということをする人がいる位なので大事です。

シェル

ubuntu環境ではシェルスクリプトを用いて、面倒なことを自動化するプログラムを簡単に書くことが出来ます。次のような手順を考えてみましょう。

  1. ソースコードをmakeでコンパイルする
  2. 拡張子が.inである入力ファイルを列挙する
  3. それぞれの入力ファイルの名前とa.outの入力としたときの出力の対を列挙する

このような手順を自動化するために、次のようなシェルスクリプトtest.shという名前で置いてください(hoge.shなどでも可)

#!/bin/bash
make
for name in *.in
do
    echo $name
    ./a.out < $name
    echo
done

そして実行するために以下のようにします。

chmod u+x test.sh # 1度すればそれ以降は不要
./test.sh

すると以下のように表示されます

ファイル名1.in
出力

ファイル名2.in
出力

...

シェルは強力なので簡単な書き方は覚えておきましょう。

ICPC台湾2019参加記

チームThinkMETの一員Enderedとして、今回参加しました。

 

[-n日目]

emacsのflymakeをおすすめされる。vimを擁護するのが難しい。悲しい。

https://github.com/Endered/library/blob/master/onsite/vimrc

なので、vimにもflymakeモドキを実装。セーブすると構文チェック後ハイライトしてくれます。

実装が汚いのと、あまりvimを理解していないため、注意。

 

[0日目]

起床後、家を出る。

友人に暴れてこいと言われた、嬉しい。

頑張るぞ〜。

 

tekiheiさんとS_ZKさんと駅で待ち合わせ。

全員集合30分前に集まって、真面目だなぁと思いながら1時間後に電車に搭乗及び出発。

 

DIVINFの人たちと空港で集まって、飛行機に搭乗。

途中mo3tthiさんに神ゲーを進めてもらってインストールしたが、100MBのゲームでインストール数十分、解せない。

 

飛行機の座席にチャット機能があって、先輩たちと談笑。

tekiheiさんとS_ZKさんを巻き込もうとして、間違って関係ない人を誘ってしまう。

すみません。

その後ゆるキャンをみて癒やされてたが、両隣のおそらく中国人が視線をずっとこっちに送ってくる謎が発生。でもゆるキャンは譲れない。

 

ホテルに到着。予想より良い部屋で満足、でもリンスが足りない。就寝。晩御飯は吉野家でした。

 

[1日目]

起床。朝御飯に吉野家に行って豚丼を注文。

紅茶を頼んだら、レモンティーが出てきた。

おいしい。

 

mo3tthiさんのおすすめの神ゲーが面白く一日中していた記憶。

台湾料理を食べたくて店に移動、油そばを食べる。

台湾の人たちの郷土料理愛に敗北。

 

 

〜〜〜〜〜以下、プラクティス〜〜〜〜〜

 

tekiheiさんとmoritaoyさんは問題分を読む作業で私は写経担当。

開始5分程度でvimのエディタを書いて更に5分程度でemacsを写経。

emacslispなので書いてて楽しい反面vimとの相性に苦しむ。

そもそも、エディタの写経が10分近くかかるのはチームとしてよくないなぁと思う。

でもvimは楽しい。

 

写経後問題が渡される。

おそらくD問題を渡され問題分を読むけれどもTOEIC330点の実力にかかれば文章の大半が読めない。

なので、書いてある絵とサンプルで概要をエスパーして書いてみる。「WA」

誤読に気づく(読んでませんが)、修正。「WA」

DPですれば通るでしょう。「WA」

遷移の書き方を間違えてた、修正。「WA」

うん。諦めて、Judgeの許容を調べる。

100億回の計算が通る、びっくり。

ほかチームが、恐ろしい人数Dを解いていて悲しい。と思ったら予選と同じ問題らしい、安心。

〜〜〜〜〜以上、プラクティス終了〜〜〜〜〜

 

 

終了後近くにあった、餃子屋さんで餃子を購入して、配られた弁当と一緒に食べる。

餃子がびっくりするくらい美味しい。

なぜ、倍買おうとしなかったのか悔やむ。

 

DIVINFの人たちも集まり、どうやらOkさんが踊るほど美味しい食べ物が弁当にあるらしいのでtekiheiさんのを拝借して冷蔵庫に保存。

邪念が飛んできたような気がするので、moritaoyさんがtekiheiさんで祓う。

その後DDCCに参加。DとEがパズルと実装だったので通す。105位、嬉しい。

翌日が大会なので就寝。

リンスが欲しい。

 

 

[2日目]

起床。吉野家。牛丼。もちろん紅茶の代わりに味噌汁を注文。

コンテストがあるので急いで移動、1時間待ちぼうけ。暇ぁ。

 

コンテストが15分遅れる、ワクワク。

 

〜〜〜〜〜以下コンテスト〜〜〜〜〜

 

写経。相変わらず、すごく長いテンプレ。

問題Iを渡される。

全探索な気がするので書く。どうしても書けない、悲しい。

 

損切りをして。KHをもらう。

読む、数式を見る。標準入力と標準出力を見る。

大体入力と、出力が二乗に近い感覚がしたので適当にエスパーをすると、解法が生える。やった〜。

通った。

隣でmoritaoyさんが異様なくらいWAを生やしていてWAの歌を歌う。二人で輪唱。

 

次に、HKをもらう。どう見ても蟻本の丸パクリ問題な気がするので書く。2分後にAC。

 

問L、どう見ても凸法は必須なので書く。

しゃくとりをすると、とても早いため、余裕で間に合う。「WA」

どうやら、凸法をして三角形になったときに別の処理がいるらしい。「WA」

???どうして幾何問題なのに小数のフォーマットがあるんだろう???

テレテレ〜to_string〜。「WA」

よく見ると答えがlong longの範囲内でした。「AC」

 

次、B。

直感的に貪欲かなと考え、書く。「WA」

木DPかな。「WA」

伝達ミスに気づく。修正。「WA」

伝達ミスの伝達ミスに気づく。修正。「WA」

 

終了〜

8完で18位。国内1位!でも、ひと桁になりたい。

来年に期待。

〜〜〜〜〜以上コンテスト〜〜〜〜〜

 

終了後、ビュッフェを食べる。

料理に、素の唐辛子と生姜が入ってた。涙が出そう。

夜市へGO。

人多い、匂いやばい、KO。

マンゴージュースが癒やし過ぎて感謝。

お好み焼きをテイクアウト。

 

〜〜〜〜〜帰宅中〜〜〜〜〜

Q:tekiheiさんがABCを参加したそうにしている。私はどうしますか?

A:開始して十数分立っているので、止める。

そしたら、問題を読むだけと言ったので、一安心。

 

〜〜〜〜〜ホテル到着〜〜〜〜〜

ThinkMETのメンバーでテイクアウトしたお好み焼きを食べてみる。

牡蠣入りのお好み焼きなのですが、甘めのソースが牡蠣の内臓の苦味を中和して旨味を引き立てるような味でとても美味しい。最高。

ブログを書くのをおすすめされたので書いてみる。

これくらいに気楽に書けたら大学のレポートも週一でも余裕で出せるのに。

tekiheiさんが何かしていたので聞いてみる。

・・・・・・・・・ABCに提出してた・・・無茶しやがって

 

翌日が5時おきなので早々に就寝。をするつもりでしたが喉が乾き、コンビニで買い物。

 

〜〜〜〜〜コンビニ〜〜〜〜〜〜

0日目にも買い物をしていたのですが、そのとき驚いたこととして、レジ袋が80円くらいだったことでした。

なので、教訓を活かして大量買いを決行。

アイスとお茶をそこそこ取ってレジに行く。

私:"Please bag"

店員:"OK"

レジ:8円増加

 

Oh No

 

〜〜〜〜〜ホテル〜〜〜〜〜

 部屋に冷凍庫がないことに気づき、tekiheiさんにおすそわけしようとする。が、歯磨きをした後だった。

台湾のアイスはとても美味しかったです。

 

[3日目]

起床。着替え。さぁ、日本へ帰ろう。

 

〜〜〜〜〜電車〜〜〜〜〜

mo3tthiさんにおすすめされた神ゲーをする。

〜〜〜ダイマ開始〜〜〜

GolfBlitz ゴルフなのに乱闘に近い要素もあって面白いです。

〜〜〜ダイマ終了〜〜〜

 

〜〜〜〜〜空港〜〜〜〜〜

空港で朝御飯を食べることになり、散策。

ラーメン店らしき店で、天丼という文字が見えたので注文。

ラーメンが出てくる。

う〜ん、美味しい。

 

〜〜〜〜〜空〜〜〜〜〜

CA:"chicken rice or meat source spaghetti"

私:"chicken rice please (お子様ランチみたいだなぁ)"

チキンが添えられた白米が出てくる。

(´・ω・`)

 

ゆるキャンを帰りも視聴、やはりゆるキャンは最高。

 

〜〜〜〜〜日本〜〜〜〜〜

moritaoyさんtekiheiさんS_ZKさんと東京から会津へ移動。

 

ものすごい硬いと有名な東京駅のアイスをもらい、食べる。

硬い、けどその分味がしっかりしているので好みな味でした。

 

先輩にクソゲーを教えてもらい、ずっとぐるぐる回す変な人をしていました。

結果、指紋認証の反応が微妙になりました。

 

晩御飯として、郡山駅近くの混ぜそば店で食べる。

二年ぶりに来たので、同じものを注文。すごく美味しい。

日本の料理を久しぶりに食べて、まったりしました。

 

〜〜〜〜〜郡山駅会津若松駅〜〜〜〜〜

英語の課題が今日締め切りなのを思い出して、急いで解く。なんとか間に合った。

 

クソゲーの雰囲気のするゲームを見つけてそれをインストール及びプレイ。とてもおもしろい。

クソゲーが面白いゲームのときは神ゲーと呼ぶのだろうか。クソと神は紙一重だなぁ。

 

〜〜〜〜〜家(今)〜〜〜〜〜

帰宅後、ブログを書く。

一日で書き方が変わっているような気がするが、成長したのだろうか。

 

友人にあずきバーをもらう。

なにこれ、硬い、歯が痛い、ヤバイ。

 

〜〜〜〜〜終〜〜〜〜〜