AtCoder Beginners Selection を ImageMagick でやってみた!

はじめに

ImageMagickというプログラミング言語があることを皆さんはご存知でしょうか?

imagemagick.org

この言語は汎用的なプログラミング言語のはずなのに、何故か画像処理用途としてしか使われていないようです。もったいないですよね。 そこで、プログラミング言語ImageMagickの汎用性を広めるべく、競プロ入門に最適な問題が集まっている AtCoder Beginners Selection - AtCoderImageMagickで解いてみました! この記事を読んでぜひ皆さんもImageMagick競技プログラミングを始めてみてください!

0問目 cat

まずは前提として入出力処理の書き方から始めましょう。 ImageMagick では入力のバイト列を受け取ってそのまま出力するcatプログラムは以下のように書くことができます。

convert -depth 8 -size 1x1 gray:- - 

実際に echo "いめーじまじっく" | convert -depth 8 -size 1x1 gray:- - と実行すると いめーじまじっく と表示されます。各コマンド・引数の意味は以下の通りです。

  • convert : ImageMagickが提供するコマンドの一つ。画像変換をしたそうなコマンド名前ですが、そんなことはさせてあげません。
  • -depth 8 : 入力文字列を1バイト単位で処理するための引数です。何も指定しない場合 -depth 16 となり 2バイトずつ処理してしまうので注意です。
  • -size 1x1 : 1x1毎に区切るための引数です。
  • gray:- : - は入力を(ファイルでなく)標準入力から取るという意味です。 gray:-フォーマットを指定(raw gray)しています。

1問目 ABC081A - Placing Marbles

それでは早速解いていきましょう。この問題は、0 or 1 の s_0,s_1,s_2が与えられるので、足し算をするだけの問題です。 例えば 入力101には 2 を、 入力 000 には 0 を出力します。この問題のImageMagickでの解答コードは以下になります。

convert \( -size 1x1 -depth 8 gray:- \) \( -fx '
sum = (u[0] - 48/256) + (u[1] - 48/256) + (u[2] - 48/256);
i == 0 ? sum + 48/256 : 10/256
' -resize '2x1!' \) -

このコードを code.sh として保存し、実際に echo "101" | sh code.sh と実行すると 2\n が表示されます。 各引数の意味は以下の通りです。

  • \( -size 1x1 -depth 8 gray:- \) : 先程の例と同じく入力を1バイト単位でパースします。
  • \( -fx '...' -resize '2x1!' \) : ↑のパースにより、入力は配列 u の中に保存されています。これを -fx というオペレータ を使って頑張って望む出力に変換します。ImageMagickでは予め出力のサイズを定数で定めておく必要があるので -resize '2x1!' として出力は2バイト(答えと改行)であると宣言します。1

さて、-fx の中身は以下でした。

sum = (u[0] - 48/256) + (u[1] - 48/256) + (u[2] - 48/256);
i == 0 ? sum + 48/256 : 10/256

u[0] などの中身は[0,1]の範囲で正規化されたASCIIコードとして入っており、'0' なら 48/256 が、 '1' なら 49/256 が格納されています。 i == 0、つまり出力の1文字目ならその総和sumを正規化されたASCIIコードとして出力し、そうでない場合、つまり出力の2文字目なら '\n' のASCIIコードである 10 を 正規化されたASCIIコード 10/256 として出力しています。直感的ですね!

2問目 PracticeA - Welcome to AtCoder

以下のようにスペース区切りの3つの数字(範囲は[1,1000])と文字列(長さは最大100) が与えられるので、その数字3つの和と文字列を出力する問題です。

72
128 256
myonmyon

があれば

456 myonmyon

と出力するわけですね。この問題のImageMagickでの解答コードは以下になります。

convert \( -size 1x1 -depth 8 gray:- \) \( -fx '
for((qa=0,qx=0),abs(u[qa]-10/256)>=1/256,(qx=qx*10+floor(u[qa]*256-48),qa++));
for((qb=qa+1,qy=0),abs(u[qb]-32/256)>=1/256,(qy=qy*10+floor(u[qb]*256-48),qb++));
for((qc=qb+1,qz=0),abs(u[qc]-10/256)>=1/256,(qz=qz*10+floor(u[qc]*256-48),qc++));
sum=qx+qy+qz;
txt=i+qb+1<n?u[i+qb+1]*256:0;
ia=floor(sum>=1000?sum/1000:sum>=100?sum/100:sum>=10?sum/10:sum)+48;
ib=floor(sum>=1000?sum%1000/100:sum>=100?sum%100/10:sum>=10?sum%10:-16)+48;
ic=floor(sum>=1000?sum%100/10:sum>=100?sum%10:sum>=10?-16:txt-48)+48;
id=floor(sum>=1000?sum%10:sum>=100?-16:txt-48)+48;
ie=floor(sum>=1000?-16:txt-48)+48;
(i==0?ia:i==1?ib:i==2?ic:i==3?id:i==4?ie:txt)/256
'  -resize '110x1!' \) -

このコードを code.sh として保存し、実際に echo "72\n128 256\nmyonmyon" | sh code.sh と実行すると 456 myonmyon\n と表示されます。 各引数については先程の問題と同様の仕組みです。出力の長さは最大110文字なので、-resize '110x1!' とし、なにもない場合は '\0' を出力しています。 このコードの -fx は冗長ですが、本質的には以下のようなコードとなります。

for((qa = 0, qx = 0), u[qa] != 10/256, (qx = qx*10+u[qa]*256-48, qa++));
for((qb = qa+1, qy = 0), u[qb] != 32/256, (qy = qy*10+u[qb]*256-48, qb++));
for((qc = qb+1, qz = 0), u[qc] != 10/256, (qz = qz*10+u[qc]*256-48, qc++));
sum = qx+qy+qz;
txt = i+qb+1<n ? u[i+qb+1]*256 : 0;
ia = sum>=1000 ? sum/1000 : sum>=100 ? sum/100+48 : sum>=10 ? sum/10+48 : sum+48;
ib = sum>=1000 ? sum%1000/100+48 : sum>=100 ? sum%100/10+48 : sum>=10 ? sum%10+48 :32;
ic = sum>=1000 ? sum%100/10+48 : sum>=100 ? sum%10+48 : sum>=10 ? 32 : txt;
id = sum>=1000 ? sum%10+48 : sum>=100 ? 32 : txt;
ie = sum>=1000 ? 32 : txt;
(i==0 ? ia : i==1 ? ib : i==2 ? ic : i==3 ? id : i==4 ? ie : txt) / 256

ImageMagickでは内部的にはQ16で処理するので素朴に書くと精度の問題で想定と少し異なった出力をしてしまいます。そこで元のコードでは適宜floorを入れたりしているわけですね。 コツとして、128/256と129/256あたりの境界に注意しておくと吉です。 ImageMagickの変数名には数字が使えないので適宜a,b,c,とアルファベット順でこのコードでは変数を宣言しています。変数の説明は以下の通りです。

  • qa : 最初の改行文字のindex
  • qx : 1つめの数字を10進数としてパースした値
  • qb : 2つ目の区切り文字である空白文字のindex
  • qy : 2つめの数字を10進数としてパースした値
  • qc : 3つ目の区切り文字である改行文字のindex
  • qz : 3つめの数字を10進数としてパースした値
  • sum : 答えとなる3つの数字の和
  • txt : 文字列を出力する場合、その出力場所で出力すべき文字。 n は入力の長さが入っています。
  • ia..ie : 1文字目から5文字目までは文字列を出力するか数字を出力するか入力に依存するので、それに応じて分岐して計算した出力文字。

最後に

画像処理だけでなく競プロまでできるなんて、ImageMagick は最高のプログラミング言語ですね。みなさんもぜひImageMagickで競プロをしてみてください!

なお、僕はここまで解いただけでやる気力が失せたので、もうImageMagickを画像処理用途以外には使わないと思います。


  1. 実は頑張れば出力を可変長にできるかもしれません。

猫島でねこがねこでほわわぁぁぁ

みやぎけんのいしのまきにねこのしまがあってね

https://pbs.twimg.com/media/Elywit7VgAAT959?format=jpg&name=medium

ねこがたくさんいてね

https://pbs.twimg.com/media/ElywnRwUYAA2tpy?format=jpg&name=medium

ねこがねこで

https://pbs.twimg.com/media/ElyxDsPVgAE-eI7?format=jpg&name=medium

ねこねこで

https://pbs.twimg.com/media/ElyyTiYVMAAF5eE?format=jpg&name=large

ねこー!!!!!!!!ってなって

https://pbs.twimg.com/media/Ely0v_HU8AEGR1X?format=jpg&name=large

ねこほわぁ!!!!!ってねこで

https://pbs.twimg.com/media/Ely2dJ3VMAA9xHL?format=jpg&name=large

ごくらくねこねこねこで!!!!!!

https://pbs.twimg.com/media/Ely5ILqUcAAtMSV?format=jpg&name=large

もう!ぐへへへへ!!!!!!!!ってかんじで

https://pbs.twimg.com/media/Ely5gFqVMAA8ee7?format=jpg&name=large

ぼへぇぇ!!ねこ!!!ねこ!

https://pbs.twimg.com/media/Ely9gBTU8AInItQ?format=jpg&name=medium

うへへへへへへ

https://pbs.twimg.com/media/Ely9vDAU0AABwn2?format=jpg&name=medium

ぐへへぐへぐへ

https://pbs.twimg.com/media/ElzEP7nU4AEPIUU?format=jpg&name=large

ねこ!ほわあぁぁぁぁ!!

https://pbs.twimg.com/media/ElzER8FU8AALnsE?format=jpg&name=large

ISUCON10予選の感想戦をして7827点を出した

はじめに

弊チーム百万円ドリブンのISUCON10の本戦出場が決まりました。

予選当日の動きはメンバーのgnuの記事aokabiの記事 に書かれているのでそちらを御覧ください。チームメンバーが最強なので僕は歌って踊っていただけで突破できました。感謝。僕は当日色々躓いたりして結局まともに貢献できなかったのでまじで感謝...

f:id:CHY72:20200922234135p:plain

ISUCON用にこういうDBとの関係性可視化ツールを作っているので毎回使っているのですが、今回の予選の問題は上図のようにシンプルな関係となっており、非本質的な部分が削られているのだなぁと感じました。

感想戦

さて、予選が終わった段階で21位・2281点のスコアが出ていたのですが、我々は百万円ドリブンなので百万円にしか興味ありません。限界までチューニングをします。

予選当日でメンバーが重たいところを殆ど潰してくれたので、残りは getLowPricedChairgetLowPricedEstatesearchChairssearchEstates だけでした。この記事ではこの処理をオンメモリにしてMySQLへの問い合わせオーバーヘッドを無くすというチューニングを行い、7827点を出します。 リポジトリはこちら。

chair, estate のオンメモリ

よく見るとchairs・estateのデータはそれぞれ35000件しかありません。またメモリも潤沢に2GBあるため、まるでオンメモリにしろと言われている気配すら感じます。Goのアプリ上でオンメモリにし、データの検索・追加・更新をO(logN)で行いたい気持ちになります。

getLowPricedChair, getLowPricedEstate

こちらは要するに、「データ全N個の中から値段の昇順でK個取得せよ」というクエリです。 データはオンラインで更新される可能性があるため、平衡二分探索木のデータ構造(挿入・検索がO(logN)ででき、常にソートされていてk番目の値がO(logN)で取れる)に乗せればよさそうです。 ここの探索木は標準ライブラリにないため自分で書いてもいいのですが、本質ではないのでhttps://github.com/wangjia184/sortedset を使うことにします。 それぞれの値段をソートの順序として用いる平衡二分探索木を使えば簡単にオンメモリにできますね。

searchEstates

こちらは要するに「データ全N個の中から、Rent・Height・WIdthで条件を絞り込み、Popularityの降順で並べたときに、[A,B]番目のデータを取得せよ」というクエリです(本当はFeaturesも見る必要がありますが殆どクエリが飛んでこないので無視します)。 また、Rent・Height・Widthはそれぞれ4種類(例:Height < 80, 80 <= Height < 110, 110 <= Height < 150, 150 <= Height) のいずれかであり、絞り込み条件に含まれない場合もあります(例:Heightの指定なし)。

結論から述べると、Popularityをソートの順序として用いる前記の平衡二分探索木を計125個、5x5x5の三次元配列として持てば、O(logN)でクエリ・追加・更新にそれぞれ対応できます。 条件が4種類(例:Height < 80, 80 <= Height < 110, 110 <= Height < 150, 150 < Height)あり、それを0,1,2,3番と対応させます。条件指定なしの場合は4番と対応させます。 例えば「Rent指定なし・80 <= Height < 110・110 <= Width < 150 」のクエリは、4番・1番・1番と対応します。更新のときは0~3番の対応するものと4番を更新すればよく、計8(=23)箇所更新すればよいですね。

searchChairs

こちらも殆どsearchEstatesと同じですが、条件が更に追加で3つ(Color, Kind, Depth)増えます。 これらの条件も同様に扱うと、前記の平衡二分探索木を計56875(=5x5x5x7x13x5)個、5x5x5x7x13x5の六次元配列として持てばO(logN)でクエリ・追加・更新にそれぞれ対応できます。 更新が64箇所必要ですが、まぁこれは仕方がないでしょう。 これを愚直に実装すると余裕でメモリ制限2GBはオーバーするので気をつけましょう。僕はこれでswap領域を作らずにメモリを食い尽くしたせいでサーバーが1台死んでしまいました

さいごに

やったことはISUCONというより競プロですね。

感想戦として上記の残りネックになっていた箇所に対してオンメモリ対応をすることで7827点を出すことができました、やったぜ。

追記:当初は7670点として記事を公開していましたがもう一度回したところ7827点が出たので更新しました。

最高のインターネットと文脈の破片たち

この記事は KMC Advent Calendar 2019 - Adventar の13日目の記事です。

adventar.org

前日の記事は zeke さんの EDPC A~M問題についての備忘録 - Qiita でした。

ところでこの記事は怪文書の類の記事なので、 怪文書に慣れていない人は明日の Strelka さんの 闇鍋をした話 - strelka_dogのブログ を読みましょう!

はじめに

「最高のインターネットは文脈の破片たちから形成される」

これはとある人物のインターネット上での呟きです。 これについて述べることは無粋な行為なのですが、ここではあえてその禁忌を犯してみましょう。

みなさんは、インターネットに疲れていませんか。 「○○がxxしたから嫌だった」「○○がxxしてるwww」「xxするなんて信じられません!」「バカはすぐxxする」のような呟き・投稿、 こういう悪い感情の共有は巷に溢れていて、気を付けていないといつの間にか摂取してしまい、精神が徐々に疲弊していきます。

また逆に、「○○がxxだったから嬉しい!」「○○がxxしてくれた!」「xxするの最高!」「天才はxxしている」のように、良い感情の共有も溢れています。 これらは悪い感情よりは精神への影響は少ないのですが、これも他人への劣等感が少しずつ刺激され、精神を疲弊させる原因の一つとなります。

上記をまとめると、インターネットでの感情の共有が精神を疲弊させているのではないか、という考えが導かれます。 「最高のインターネットは文脈の破片たちから形成される」とはつまり、精神を疲弊させない「最高のインターネット」は、 感情を抜き取りただフォーマットに沿った事実だけが次々と投稿される「文脈の破片」から形成される、ということを述べているのだと私は解釈しました (この解釈は私個人によるものであり、当然「最高のインターネットは文脈の破片たちから形成される」と考えた人物の解釈とは異なる可能性が大いにありますので予め断っておきます)。

#kashi-tweet

ここからは文脈の破片たちから構成されるインターネットを紹介します。 #kashi-tweet は、KMCのSlackのチャンネルの一つで、その名の通り歌詞ツイ(歌詞の一部を投稿すること)だけが流れます。 このチャンネルは2016年11月5日に突如現れ、今日まで寂れることなく残っています。

gyazo.com

#go-go-575

#go-go-575 も、KMCのSlackのチャンネルの一つで、その名の通り575(≒川柳)だけが投稿されます。 このチャンネルは2015年3月3日に現れ、今日まで残っています。

gyazo.com

Nuita

部員が作成したNuita というSNSがあります。 このサービスの内容について言及するのは不適切な気がするので、以下の記事を読んでください。

kyp.hatenadiary.com

#飛ぶことは救いではない

文脈の破片を投稿するのが上手な人が居て、その人が文脈の破片を投稿するのでそれを愛であっていました。

gyazo.com

この文脈の破片は質が高く、昨年の夏コミで本にして出しました。 現在Boothで公開中です ( 飛ぶことは救いではない合同誌 - tobusuku - BOOTH )。

応用

折角なので現実のインターネットに応用してみましょう。 今回はTwitterを「漢字の破片だけが流れるSNS」に改造してみます。

5秒で思いつく以下のjsを実行します。

setInterval(()=> document.querySelectorAll("p.tweet-text").forEach(x=>x.innerText = (x.innerText.match(/[一-龠]/g) || []).join("")),1000)

gyazo.com

gyazo.com

精神に悪影響を及ぼしやすかったあのTwitterが、文脈の破片を紡ぐ最高のインターネットへと華麗に変身しました! やったね!

さいごに

明日の記事は Strelka さんの 闇鍋をした話 - strelka_dogのブログ です。たのしみ!

ポケモン剣盾でマスボ級にいったノーマル統一パの覚え書き

だいたい「エレザードホルードメタモン」の並びになりがち。

死ニーゴとかの面倒そうな相手が2体居るときにはタチフサグマが刺さるので入れる。 (死ニーゴはナイトヘッドやたたりめでしか攻撃できないことが多い(うずしおとかもあるのにね)ため殆ど選出されないので死ニーゴだけなら無視している)。

格闘対策は、イエッサン。 ルカリオローブシンが居ると大抵出してくれるのでイエッサンで叩く。壁ロンゲもだいたい悪を見てフェアリーわざしかないのでイエッサンのサイコメーカーで処理できる。 ルチャブルダイマックスイエッサンで倒すしか無いけど難しすぎるのでこれは出てきたら負けでいいです。

カビゴンは...環境外の強そうなやつがいるときに出すと壁になってくれるけどあんまり役に立ったことがないかも...バイウールーに変えようかな...

エレザードはとにかく強くて、バンドリをきあいだまで倒せる。 エレザード先手からのスカーフドリュのじしん連打の負け筋を引かなければだいたい勝てるのでカモ。バンギから入るとほぼ勝ち。 ダイマックスじゃくほで倒されてもホルードがいればばかぢからで処理できるし、ホルードが居ない場合は最大まで積ませてメタモンでパクって全抜きできる。 サザンドラアイアントを上から倒せるのもロトムには無い強み。 相手の知識がないとエレザードに水技を打ってくれることもあるし、そうでなくてもウォッシュロトムには対面勝ちできる。

スカーフホルードが結構強くて、スカーフ・タスキ・ハチマキ・ダイマックスのどのドラパルトでも対面イカサマで勝てるほか、ドリュも対面なら打ち勝てる。 ミミッキュもじしん連打でも倒せるし剣舞積み後ならイカサマでも倒せる。

メタモンが最強で、ダイマックスして強化したりじゃくほしてくれたらそれをまるまるパクってタスキか素早さ乱数勝利で打ち勝ったあと全抜きができるほか、 普通に状況に合わせて残りのメンバーでは処理しにくい相手を強引に処理できるので最強。 スカーフよりもタスキのほうが強い。スカーフだと(ほぼ)確定対面勝ちしか利点が無いが、タスキだと技が拘られないので状況に合わせて柔軟にへんしんできる。 先制技はあんまり見ないしミミッキュはかげうち合戦するだけだし積みエースに強すぎる。 メタモンにも弱点はあって、みがわり状態の相手にはへんしんができないのと、ばけのかわはコピーできない(相手のばけのかわが剥がれていなくてもこちらのばけのかわは剥がれてしまっている)のが痛い。みがわりとばけのかわは絶対に剥がすしかない。 ギルガルドのバトルスイッチもコピーできない(キングシールドを使っても変わってくれない)ので、なるべくブレードフォルムの方をへんしんできるようにしておきたい。 あとへんしんするとPP5になるのは弱みでもあり強みでもある。最後に害悪系が残ったときにへんしんするとPPで負けてわるあがきで死んでしまう。しかし仲間が居るとPP5にしてリセットができる。隙きを見て入れ替えれば無限のPPを得られるので1回勝てた。

よくある負け筋はエレザードとアーマーガー対面からのでんき技読みスカーフドリュ変えでじしん連打されること、これを読んでイェッサンが出せれば好転するけどむずい... 後はヌオー・トリトドン・ゴリランダー・オノノクス・(スカーフ)ヒヒダルマルチャブルはかなり相性が悪い. 上三体は読んでダイマックスイエッサンで処理するしかない。下三体は自身を強化してくれないし有効打も無いのでどうしようもない。出てきたら負けです。 カビゴンをこれらに有利なポケモンに変えたほうが良さそう。

あとメタモンで環境のパーティの技構成を完全に知れるため、こちらも今後それを対策できるのが一番偉かったかもしれない

ISUCON9本戦で10万点を取るにはひたすらハードコーディングとN+1をすればよい

ISUCON9本戦の感想戦をやっていきました。最終スコアは105417点です。

github.com

最終的な avaiabledays は100。DB1台,Webアプリ1台。

f:id:CHY72:20191029072331p:plain

過去のISUCONは傾向としてトランザクションが本質になりがちな傾向がありましたが、 今回のISUCONの本質はハードコーディングとN+1でした。

TLDR;

  • ひたすらハードコーディングとN+1消しをすれば点数がどんどん上がる。複雑なトランザクションも必要ない。
  • このブログにはN+1以外のことも書いてあるが、それはあんまりネックではない。本質はN+1。
  • ただひたすらにハードコーディング作業とN+1消去作業をしましょう。

やったことまとめ

10000点くらいまでの過程は省略。

N+1

  • 各席毎にDBに問い合わせるのをやめて、対象車の予約を一括で取ってきてアプリ側で席を管理することでN+1を消す。
  • getAvailableSeatsの対象となる列車リスト(およそ10車)を予め取得してから問い合わせることでN+1を消す。
  • あいまい検索で前から順に16車両分回すN+1も消す。
  • 他にも細々としたN+1を消す。

train_masterのハードコーディング

  • そのままでは流石にハードコーディングできないので、本質的なデータだけ(Departureの時分/{東京京都大阪名古屋}のペア(6通り),TrainClass)をハードコーディングする。

train_timetable_masterのメモ化

  • 数百万通りの可能性があるのでオンメモリにはできないが、実際にアクセスされるのはそれより遥かに少ないのでメモ化する。

キャンセル処理

  • bulkする。

ログイン・サインアップ・getUser

  • 本質ではない。下記をするとほのかにスコアがあがる。
  • Cookieのuser_idのデコードに時間がかかるので、同じユーザーのクッキーのデコードはキャッシュする。
  • Userデータを https://github.com/Muratam/go-syncmapserver で管理する。
  • SHA256のハッシュの回数を10回から1回に減らす。規定はないので。

ほか

  • あいまい検索時に二重にvalidationしているのをやめる。
  • インデックスは貼った方がお得なのでちゃんと貼る。

残りできること

  • getAvailableSeatsは理論的には消せるので消す。
  • そろそろ接続が増えすぎてコネクションが辛くなってくるのでDocker外しをしたりNginxやMySQLのそういうパラメータをチューニングする
  • 外部サービスへの接続のTLSハンドシェイクが下手くそなのでプーリングする。
  • reservations/ seat_reservations もhttps://github.com/Muratam/go-syncmapserver で管理する。
  • 複数台構成をする。
  • これは予想ですが多分上記をやってavaiabledaysを366にすると 200000点くらいは出ると思います。

やらなかったこと

  • 席予約アルゴリズムの変更。やる必要がなかった。
  • ベンチがHTTP2になってくれたらもっと点数出るのになー。

サイコロの旅のすすめ

TL;DR

18きっぷが余っていたのでサイコロを振って出た目が示す所を目的地とするのを繰り返すサイコロの旅をしました。

サイコロの旅

どこに行くのか決まっている旅もいいですけど、たまにはどこに行くのか分からない旅もいいと思いませんか? このサイコロの旅ではどこに行くのかはダイスを振って決めます。 予定が直前まで分からないので管理された旅が苦手な方におすすめです。

京都発

本家水曜どうでしょうに合わせて近く4駅,遠い2駅から目的地は万遍なく選びました。 柘植とかが出るとこのあとの発展性があるんですが、今回は関西空港になりました。

関西空港

次の目的地は和歌山になりました。

f:id:CHY72:20190914123010p:plain

関西空港に来ましたが、18きっぷを使うのが目的なので海外には行きませんし、当日飛行機は高価なので飛行機を使うわけでもありません。 その日はイベントもありません。 完全に「大阪から和歌山行きに乗ったが間違えて先頭車両に乗ってしまい関西空港に着いた人」です*1

周りが飛行機で旅たとうとしているなか、我々は改札で出した18きっぷで再度Uターンします。 まあこういう完全な無駄行動もサイコロの旅の醍醐味ですね。

ちなみにサイコロの出目によっては,関西空港から神戸港のフェリーに乗ったり、すきっぷ2000というお得きっぷを使うレアな機会があったのですが、これらの目は出ませんでした、悲しい〜

和歌山

f:id:CHY72:20190914123544p:plain

徳島が出ました!フェリーか〜〜〜〜〜〜〜〜!

和歌山城・和歌山ラーメンを観光。

知っている人は知っている、和歌山の地酒高垣を売っている酒店です。

www.sankei.com

デレの不思議な縁でできた観光地になっており、前に来たときよりも随分とグッズが増えていました。 こういうところはいいですね。

フェリーに乗るとやたらとこのアニメがプッシュされていました。 「おへんろ。」という四国ローカルアニメらしいです。

どパスコが可愛かったのでツボに入りました。

徳島

f:id:CHY72:20190914123827p:plain

というわけで最終目的地は小歩危(大歩危)になりました。 歩くのが危険と書いていますが、それは昔の話で今は道も整備され電灯もあり、歩くのは容易いです。

2日目

2日目もサイコロを振ると帰れなくなるので普通に大歩危を観光して帰ります。

さいごに

サイコロを振って結果が出るまでどうなるか全然わからないのはかなり楽しいので、旅にちょっとしたスパイスをかけたいかたはぜひサイコロの旅をおすすめします。

おわり

*1:この列車は先頭4車両は関西空港に、残りは和歌山に行くことが多い