Skyrimで英語の勉強

Skyrim、PC版をちょっとずつ日本語音声で進めてたんだけど、ちょっとでも英語学習の足しになればなーと英語音声に切り替えました。

ただ、
英語音声+英語字幕:
  よく話についていけなくなる。あと疲れるので息抜きにならない。
英語音声+日本語字幕:
  英語でなんて言ったのか分からないときがある。字幕だけ見て安心する。
ってなって微妙に困ってました。

というわけで、字幕に英語日本語両方つっこんでみました。



Steam版だと国設定を切り替えれば日本版・US版の文言ファイルが手に入ります。
StringUnpackerを使えば文言ファイルをバイナリ形式とテキスト形式で相互変換できるので、テキストにして文言マージしてバイナリに戻しました。

これで勝つる!

ちなみに僕の英語学習のゴールは「洋ゲーを翻訳なしで疲れずに楽しめること」です。
英語音声・字幕なしでやるとゴールまでの距離がよく分かりますね。
いや遠すぎて分かりません。

===== 追記(2014/04/27) =====

マージした後のPackがうまくいかないというコメントを複数いただいていたので、マージを行うプログラムを書いてみました。
SkyrimStringMerger

英語+日本語字幕化の手順はこんな感じになります。

必要なもの

  • StringMerger.exe (上記zipに含まれてる実行ファイル)
  • StringPacker.exe, StringUpnacker.exe (https://sites.google.com/site/jpmodfiles/localize/skyrimにあるskyrim_strings_tools.zip)
  • Skyrim_English.ILSTRINGS, skyrim_Japanese.ILSTRINGS (英・日それぞれの字幕ファイル)

手順

  1. (準備) 上記のファイルを同じフォルダに入れる (C:\SkyrimStringsに入れたとする)
  2. コマンドプロンプトでそのフォルダを開く
    cd C:\SkyrimStrings
    
  3. 英語・日本語の字幕ファイルをCSVファイルに変換する
    StringsUnpacker.exe /IL Skyrim_English.ILSTRINGS Skyrim_English.ILSTRINGS.csv
    StringsUnpacker.exe /IL skyrim_Japanese.ILSTRINGS skyrim_Japanese.ILSTRINGS.csv
    
  4. 2つのCSVを合成したCSVファイルを作る
    StringsMerger.exe Skyrim_English.ILSTRINGS.csv skyrim_Japanese.ILSTRINGS.csv Skyrim_Merged.ILSTRINGS.csv
    
  5. 合成したCSVを字幕ファイルに戻す
    StringsPacker.exe /IL Skyrim_Merged.ILSTRINGS.csv Skyrim_Merged.ILSTRINGS
    
  6. 出来上がったSkyrim_Merged.ILSTRINGSで使用中の字幕ファイルを上書きする

私の環境ではこれで英語+日本語の字幕になりました。
役にたつと良いのですが・・・

現状「英語 (日本語)」になっているフォーマットを変えたい方もいると思うのですが、サポートしていません。やっつけですみません。
コンパイルできる方はこの辺りを変更してください。

しあわせの必要条件

17歳のころに学ぶべきこと/無遅刻・無欠席を礼賛する風潮はどうかと思います の、

しあわせの必要条件は「自由」であることだ。

に思うところあったので感じてることをメモメモ。

こんな事を書いて会社を辞めた僕がこれに共感したって書くと、仕事してない僕は自由だー!って言ってるみたいだけど、ここで言う「自由」とは、何かをしなくて良い自由というより、何をするか自主的に選択する自由と言った方が言わんとするニュアンスに近いと思う。

ここ数日、なんでかなって考えてたことがあった。
根詰めて勉強するのは体力的にもキツイし、孤独だし、思うように進まなくてイライラしたりする。
それなのに、強がりでも何でもなく、今僕は大きい大きい幸福感を感じてる。
予想してた精神状態と違う。もっとシビアなメンタルコントロールが要ると思ってた。

やりたかった事をやれてるから?ちょっと違う。今月は色々あってやれてない。焦りはあるし充実感薄い。
仕事のストレスが無いから?多少はあるかも。でもその分将来への不安とかストレスになってるはず。

そこでしっくりきてた考えがこれだった。
もしかして:今の状況を自分で選択している実感があるから

自分で考えて選択した結果が今だと実感する事は、選択の正誤に関係なく、精神的に良い影響がきっとある。多少の不安やストレスならかき消してしまうほどの。
起業家にやたらテンション高い人が多いように見えるのは、そう振る舞う必要があるだけじゃなく、選択による幸福感も影響してるんじゃないかな。
単に選択肢があるだけじゃなく、結果に責任を持つ覚悟や、自分の頭で精一杯考えたことが、選択の「実感」につながってる感じ。

必要条件なのかは分からないけど、今感じている限りすごく大きな心理的作用なので、

  • 強制的に選択を奪う不要なルールや同調圧力にはもっと敏感になろう。
  • 幸せに働いてもらうには多くの選択を相手に委ねたい。できることは最小限の制約の明示とゴールの共有。
  • 選択できる人が選択できない人に同じ負荷を強いてはいけない。
  • 限られた人しか選択できない世の中は構造的に欠陥がある。

とか考えてた。

僕は僕で、しあわせな人間が高いパフォーマンスを発揮できることをちゃんと示したいなと思ったりしています。

ソートのアルゴリズム

Googleの新卒採用向けHangoutをひやかしで見てたら、社員の方がこんな感じのことを言ってた。

Googleの面接といっても難しいことは聞かれなくて、CS(Computer Science)の人なら答えられるであろう質問だった。自分の場合だと、クイックソートを書かされて、そこから性質や計算量のオーダーなどについての説明を求められた

CSやってた人として恥ずかしくない技能を身につけたい!って思いながら毎日過ごしてる自分としては気になるコメント。
ほうほう、クイックソート…。どんなんやったっけ。うろ覚えなまま15分かけて実装するも、あえなく無限ループ。さらに30分かけてバグを取ったのがこちらのコードになります…orz 面接終わってるな。

#include <iostream>
#include <vector>
using namespace std;

void quicksort(const vector<int>::iterator begin, const vector<int>::iterator end) {
  if (end - begin <= 1) return;
  // pivotには単純に先頭要素を使う
  int pivot = *begin;

  // 両サイドから走査して、pivot未満の要素とpivot以上の要素の
  // 組が見つかったらswap
  vector<int>::iterator left = begin, right = end - 1;
  do {
    while (*left < pivot && left < right) left++;
    while (*right >= pivot && left < right) right--; 
    if (left < right) {
      swap(*left, *right);
    }
  } while (left != right);

  // [begin, left)がpivot未満、[left, end)がpivot以上なので、
  // leftを境に分割する。ただしleft==beginの時は全要素pivot以上なので
  // pivotになった左端の要素は左側の区間に振り分けて区間を小さくする
  vector<int>::iterator mid = left;
  if (mid == begin) mid++;

  // 分割した区間に対して再帰的にsort
  quicksort(begin, mid);
  quicksort(mid, end);
}

int main() {
  static const int a[] = {3, 2, 1, 2, 6, 5, 9, 1, 8};
  vector<int> v(sizeof(a) / sizeof(a[0]));
  v.assign(a, a + v.size());

  quicksort(v.begin(), v.end());

  for (int i = 0; i < v.size(); i++) cout << v[i] << " ";
  cout << endl;
}

車輪も1回くらいは作っとくべきだよね。

書いてるうちに気になったのが、STLのsortはどんな実装になってるんだろう?ってこと。検索するとSigmarさんが調べてブログに書いてくれてた。代表的な実装ではこんな感じになっているのだそう。

  1. まずはクイックソート
  2. 再帰がある一定以上深くなったらヒープソートに切り替え
  3. ある程度ソートが進んだら、最後は挿入ソートで仕上げる

手順1と2をまとめてイントロソートっていうらしいです。なるほどなるほどー
汎用的なままよいパフォーマンスを発揮するために工夫されてるんだなぁ

あと、調べてる時に遭遇した、Haskellで書いたクイックソートがかっこよすぎた。

qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

Haskellも勉強して嗜んでみたいです。

1月のまとめ

東京帰ってきてから3週間くらい。やってたことをメモメモ。

勉強した本

1対1対応の演習/数学I・数学A

やり方は、例題は5分で分からんかったらヒントだけ見てもっかい考える、演習題は20分考えて分かんなかったら答え見る、って感じ。タイマー持ってやってた。
かかった時間は1A合わせて1週間くらいだったと思う。
教科書レベルの内容を確認するために白チャートも買ってたけど結局ほとんど使わなかった。(上記本内の「要点の整理」とネットで事足りた。)

高校生1年生向けだけあって、大事な事が高密度に盛り込まれてるなあと思う。
集合、命題論理、確率とかは僕が普段考えごとする時にも基礎になってて、その部分の基本理解を固め直した事で少し頭の霧が晴れた感覚。
30分くらい集中を維持するための訓練にもなった。
終わった頃ちょうどセンターの時期だったのでやってみたけど97点でしたワーイ(現役の時より良かった!)

プログラミングコンテストチャレンジブック 第2版

まだ初級編だけ終わったとこだけど1週間以上かかってる。
中の人が頭良すぎるのか、紙面の都合なのか、基礎的な内容から急に発展的な結論に飛んだりするので、理解するために紙にいろいろ書いて考えたりWikipediaとかネット調べたりしてちょっとづつ進めた。数学の基礎なしできっちり理解するのは難しいと思う。
それでもいい本。きっと読みきれば相当の力が付く。
勉強の仕方としては、練習問題の解答とか各手法のコードを理解した後、必ず自分で答え見ずに書きなおすようにしてた。コード理解するフェーズでは写経した上でデバッグ文入れて…とかやるんだけど、その後必ずそらで1から書き直す。僕の場合は「STLを可能な限り活用する」「グローバル変数は使わない」みたいな自分ルール追加して書きなおしてたけど、違う言語で書くのも効果的だと思う。第2版から付いてくる練習問題も当然やる。

参加したコンテスト

Facebook Hacker Cup 予選 (ソースとコメント)
 o-o 646位/? 通過。
Facebook Hacker Cup Round1 (ソースとコメント)
 ooo 756位/? 通過。
TopCoder SRM 531 Div2 (ソースとコメント)
 o-o 18位/1240 Rating:1187->1303

遊んだゲーム

Skyrim (PC)
 今年いっぱいこのゲームだけで乗りきれるんじゃないかと思ってる
jubeat plus (iPad)
 むりーって思う曲もいつの間にかついていけるようになってる感覚が楽しい
なめこ栽培 (iPhone)
 中毒性を少し理解したけど2日目に飽きた

ほか

あとは手続き関係こなしたりご飯作ったりゴロゴロしたり本屋めぐったり知らない言語とかツールをつまみ食いしたりしてた。
とにかくすっごく長く感じた。2月以降も長いといいなあ。

ソニーを退職しました。

(社内で出した退職メールを一部削り、よく聞かれた質問への答えを追加したものです)

本日2011/12/28を最終出社日として、ソニーを退職しました。

振り返ると本当に多くの人の支えで恵まれた生活を送ってきました。一方で、望む生き方のために必要と認識しながら未熟な能力を出来る限り短期間で補完するため、もう一度勉強に専念する時間が欲しいという思いも持ち続けていました。そんな中いくつかのタイミングが重なり、今回わがままを言って退職させていただきました。

ソニーでの生活

コクーンで興味を持ち、設立趣意書に惚れてソニーに入りました。入って最初の印象は「研究室みたいだな」という感じで、予想していた学生から社会人へのギャップをほとんど感じなかったのを覚えてます。とにかく最初から居心地が良かったです。

最初の年、自分はまだ戦力になっていませんでしたが、少数精鋭のチームが全力をあげて無茶な目標を達成する様子を内側から見ることができました。次の年からは、製品に乗るコードを書くことがどういうことかを学びました。不具合で市場問題が起こるとどんな影響があるのか、品質を保証する難しさと方法を学びました。長期間広く再利用されるモジュール開発を通じて、API設計の考え方と重要さを学びました。UIアプリ開発では実行パフォーマンスが持つ力を認識し、改善手法を学びました。自分が出したアイデアが製品に乗って無数に出荷され、フィードバックが来る楽しさを知りました。サービス設計ではオフラインアプリ設計との様々な考え方の違いを学びました。たびたび海外にも行かせていただいて、出不精な僕でも少し各国の環境・文化・考え方の違いに触れることができました。

どれもこれもかけがえの無い経験です。

今振り返ってみると本当にたくさんの方の助けでやりたいことをやらせてもらい続けていたと思います。エンジニアとして非常に恵まれた環境で長い時間を過ごすことができました。

なぜ辞めたか

辞める決意が固かったわりに、その理由は少し漠然としてます。

30才を過ぎた頃、結局僕は残された時間何をして生きるのかをようやくまじめに考えはじめました。そこでしっくりきたのが、「40代になっても50代になっても、幅広く技術を使いこなしながら、自分が面白そうって思ったものを作っては壊し作っては壊しできたらめちゃくちゃ楽しく生きられそうだなあ」というイメージでした。図画工作や美術ばかり常に全力だった過去も、自分が創作活動で強い幸福感を得られる性質であることを裏付けているように感じました。

だけど、「作るの好き」だけでは生計は立てられません。やりたいことだけははっきりしたので、どうやったらそれで生活できるか考えました。それで出た答えは単純で「もっと作る力を高めよう」でした。

理由の一つは、自信を持って創作に集中し、価値を生む確率を高めるためです。採用面接でも使ったレースゲームへのたとえ話をしてみます。走り方(ライン取り・車種選択等)が同じ相手に対しては、走りこめば自分も同じタイムを出せる自信がありました。だからこそ僕は上位の人の走りやタイムをあまり気にすることなく、速い走り方を試行錯誤して探すことだけに集中できて、結果的に独特な走り方で世界記録を出せたりしていました。そんな学生時代の成功体験を引きずっている僕は、まわりに振り回されず本質的な創作に集中するために自信が必要と考えています。同じアイデア・コンセプトで作れば自分が負ける、と思っている限りきっと僕は動けない気がしてます。

また、作るものの規模が少し大きくなるとどれだけ頑張っても一人では作れなくなります。それに、作る人だけいれば良い訳ではなく、お金や価値を生み出すには色々な役割の人が組まないといけません。大きな力を持った人達とチームを組みたいのであれば、自分も最大限の「作る力」を提供する必要があると考えました。

そんなわけで、とにかく今はソフトウェアを作る力を全力で伸ばすのが望む生き方への近道だと考えています。

仕事しながら勉強する選択肢もありましたし、そのつもりで1年半ほど前には技術の幅を拡げるべく違う領域へ異動させていただきました。特に最初半年は毎週末技術書を買って土日で読む感じでしたが、めちゃくちゃ楽しかったのを覚えています。仕事をしながらも多くを学べたし、仕事を通じてしか学べない事も多くありました。それでも、勉強したいことの量とこなせるペースのギャップには焦りを感じていて、いったん仕事を止めて時間や気力を100%勉強に全振りした場合にどこまでやれるか確かめたい気持ちは強くなる一方でした。そうして、このタイミングで実行することを決心しました。

甘い状況判断から危ない選択をしたのではないかという不安はあります。だけど、世の中はもっと厳しい「はず」で冷静になるのも嫌なので、外に出て、全力でやってみて、それでも力不足なら早めに失敗しよう、どの考えが甘かったか実経験から反省してまた頑張ろう、とも思っています。

勉強したいこと

基礎力としては、「柔軟で実行効率の高いコードを、早く正確に書ける」とか、「新しい技術を正確に理解し、正しく使用できる」みたいなイメージを目指していて、数学やアルゴリズムとデータ構造なんかに始まってコンピュータサイエンスの基礎を体系的に学び直したり、言語への理解を含めたり、知識をちゃんと運用できるように訓練したいと思います。初見の技術を正しく捉えるためにもしっかりとした基礎が重要だと、仕事を通じて学びました。

また、「今どんな技術があって、何ができるかを幅広く具体的に知ってる」ようにもなりたいです。僕は何かアイデアを探るときに「あれをあれに応用するとどうなるかな」みたいにシーズベースで考える傾向があります。その意味で、僕の発想の幅は知ってるシーズに強く依存しそうです。であればたくさん知ることで強化したい。それらの技術を具体的に知るには、使って何か作ってみるのが一番と思ってます。それを可能な限り幅広い技術に対してやってみたい。とにかく幅広く。多くの技術をちゃんと理解することは、発想の種になるだけでなく、実現したいことに対して数多くの技術から最も筋のいい方法を選ぶ力にも繋がると思ってます。

フロントエンド・バックエンド両方をしっかり作るため、UIやデザインに関しても基本を勉強したいと思っています。

これから

力はついたけどその後の生活苦しいというパターンでは、きっと後悔しないと思います。後悔するとしたら、力がつかなかったパターン。モチベーションが続かないのが一番怖いです。今回の決断で迷惑をかける多くの方にも全く申し開きできません。でも、2年間勉強したい気持ちは高まるばかりだったのを確認してからなので、ある程度の勝算はあるんじゃないかと思っています。

というわけで、来月からは無職になり、多分人生最後(?)の「勉強専念タイム」を過ごします。

今までいろんな人に育ててもらい、助けてもらいながら、100%自己中心的な理由で突然離脱するにも関わらず、考えをじっくり聞いてくれて応援して送り出してくれる上司や同僚達には感謝してもしきれません。この会社で皆さんと仕事ができたことは本当に幸運でした。

これからの勉強時間が、まだ20年以上続けるつもりのエンジニア人生をより楽しくすると信じて、また、何らかの形で恩返しに繋がると信じて、思いっきり頑張ろうと思います。

今までありがとうございました。
そして、これからもよろしくお願いいたします。

続きを読む ソニーを退職しました。

6×8=48は正解でも8×6=48は間違い…について考えた

6×8=48は正解でも8×6=48は間違い…今の小学校、記述順にこだわり

初見の感想は「どうでもいいwww」なんだけど、昔よく算数教えてた頃を思い出してちょっと考えさせられた。

順番にこだわる理由はこんなカンジ?

  • 本質的には 6(本/人) × 8(人) = 8(人) × 6(本/人) = 48(本)
  • でもまだ交換法則も習ってないし(本/人)みたいな単位や単位変化も習ってないので、6(本ずつ) × 8 = 48(本)という教え方をしている
  • ベースになっている単位が何かを意識させるために、順番は厳密にしている
  • このあと習う割り算では特にベースの単位を頭に持ってくる必要があるので、順番を意識する習慣をつけさせる

前提知識の無い子供にstep by stepで教えていく必要がある場面での考えとして理解できる部分はあるけど、僕は反対。

  1. 子供に納得できるように説明できるの?この事情をわかるように説明するのは交換法則の説明より難しいと思う。不正解としてバツを付けるのはインパクト大きい。ましてや理由が理解できない場合は無駄に苦手意識を植えつけたり学習意欲を削いじゃったりしかねないよ!
  2. スコープを絞って教えるためにスコープ外を不正解扱いにしちゃうのは、自由な発想や応用力を制限してしまう結果になると思う。

掛け算なんて「くりかえし」くらいのイメージでふわっとつかんでた方が応用きくと思うんだよね。別に「8人に1本ずつ配るのを6回繰り返す」のをイメージしてもいい。ていうかそう文章題に書かれても対応できてほしい。

文章題になると極端に点数が下がる子もいたけど、そういう子にとって文章題は「日本語を決められたルールに従って数式に変換する作業」だったのかなと思った。だから準備してない表現が出てくると意味は分かってても固まる、と。今回の例だと「ずつ」を探す子は「一人あたり」に言い換えられるだけで手が出なくなったり。

文章題の内容をシーンとしてイメージしてから数式で表現するって、算数では当たり前のプロセスのはず。そのプロセスを身につけさせるためにも、特定の日本語表現に数式を対応付けるような教育はして欲しくないし、シーンを数式で表現する時のいろんな解釈を制限しない教え方をしてほしいなあと思う。

でもこんな些細な話でもいろんな意見あって教育ってムズカシイネ

iPhone4(SB) vs iPhone4S(au)で通信速度比較

いろいろ間違えてiPhone4(Softbank)とiPhone4S(au)の2台持ちになってしまったので、簡単に速度比較してみました。
Softbankの方は4Sじゃない点にご注意ください。あと測定アプリが怪しい可能性もあります。

ビックカメラ有楽町店 地下ゲーム売り場 (閉店間際。人はまばら)

左がSoftbankのiPhone4, 右がauです。

平均は、SBが400KB/s, auは1100KB/sくらい。

有楽町駅ホーム (22時過ぎ。やや混雑)

SB 900KB/s, au 1100KB/s。 誤差の範囲か。

田町駅改札前 (22時過ぎ。あまり混んでない)

SB, auともに平均は1000KB/s程度

ヨドバシカメラ前 (早朝 / Vita予約行列内)

SB 1100KB/s, au 1500KB/s

まとめ

「屋内はau、屋外ではバラつき具合に違いがあるもののトータルではそれほど変わらない」っていう評判を追試しただけになってあまり面白い結果ではなかった…
あと、ダウンロードスピードは上記の通りなんですがダウンロードが始まるまでの待ち時間はSoftbankが長いことが多かったです。
これまでSoftbankでストレス感じてたのは主にこの点なので、auも増えてくるとどうなるか分からないけど今のところ満足。

GCJ Japan 決勝 参戦記

ぶっちゃけAしか合ってないので、解き方についてはなんも言えない。
結果は15点/penalty 36:23で162位。なんとか目標のTシャツには届いてた。
参戦しながら考えてたことを参戦記としてだらだら書いてみる。

B. バクテリアの増殖

  • 開始。5問もあることにびびる。点数配分をみて、なんとなくBかCを早めにとけばTシャツいけんじゃないかと根拠の薄い仮説を立てる。
  • Bを読む。ふむふむ。バクテリア増えすぎやろ。宇宙がやばい
  • 多分、周期がありそう。でも周期発見するまでに溢れまくりそうだ。(ab+c)^(ab+c)を展開してmod bに関係ないとこ外さないといかんかな?
  • ああ、数式の展開とか全然できない自分の頭がうらめしい。後回し。ていうか多分できない。
  • 次はCにトライ!するつもりだったけど、なんとなくしょんぼり状態になったので勢い付けたい。Aいこう。(終わってみれば、ここでC行ってたらTシャツもらえないところだった。)

A. アンテナ修復

  • ああ、これは直感的には、長い棒から順に、右に置いて、左において、って感じで長い棒を片方に寄せれば面積最大になりそう。
  • 証明…はいっか。他のやりかた思いつかないし、Aだし引っ掛けもなさそう。それで解いちゃえ
  • #include <iostream>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    const double PI  = acos(-1.0);
    
    double solve(vector<int>& E) {
        sort(E.begin(), E.end());
        // 短い方からE0, E1, E2...とすると、円周上で... E4 E2 E0 E1 E3 ..
        // みたいに並ぶよう並び替える
        vector<int> ordered;
        for (int i = 0; i < E.size(); i++)
            if (i % 2 == 0) ordered.push_back(E[i]);
        for (int i = E.size()-1; i >= 0; i--) 
            if (i % 2 != 0) ordered.push_back(E[i]);
        
        double answer = 0;
        for (int i = 0; i < ordered.size(); i++) {
            double e1 = ordered[i];
            double e2 = i != ordered.size()-1 ? ordered[i+1] : ordered[0];
            answer += e1 * e2 * sin(2 * PI / ordered.size()) / 2;
        }
        return answer;
    }
    
    int main() {
        int T; cin >> T;
        for (int i = 1; i <= T; i++) {
            int K; cin >> K;
            vector<int> E(K);
            for (int j = 0; j < K; j++) cin >> E[j];
    
            double answer = solve(E);
            cout.precision(10);
            cout << "Case #" << i << ": " << answer << endl;
        }
    }
    

C. ワイルドカード

(※ 以下は最初から問題取り違えたまま右往左往した記録でありなんの参考にもなりません)

  • 気を取り直してCをオープン。なんか昨日チャレンジブックで読んだしゃくとり法が使えそうな気がする!
  • しゃくとり法で、Bには存在しなくてかつできるだけ短いAの部分文字列を見つける。なんとか実装。sample通ったのでsmall提出。不正解。
  • A:dz, B:ddzzのパターンうまくいってない。解が見つかってない様子。dzはBの部分文字列だけど、*がないdzはBから識別可能なのか。最初と最後の文字は区別する必要あるのね。
  • AとBの文字列それぞれの頭と終わりに文字をくっつけるアプローチ。A’:SdzE, B’:SddzzEに変換して部分文字列を見つける処理にする。さっきのパターンは通ったけど不正解
  • A:fmmfmmfmm, B:fmmfmmのパターンでうまくいってない。正解は*fmm*だけど、fmmがBの部分文字列になってるので見つかってない。頭と終わりに文字くっつけるのじゃだめか。じゃあ頭と終わりを大文字にする A’:FmmfmmfmM, B’:FmmfmMとやる。これでこのパターンは正しくなったけどやっぱり不正解。
  • A:ororor, B:or のパターンでうまくいってない。正解は*orだけどor*になってる。*o*がAを識別できるために、しゃくとり的にoが削られて最後のorが繋がってくれてない。あれ?しゃくとり法したのが間違い?
  • 〜Cで2時間経過〜 あと30分だ!シャツのためには、どれかSmall総当たりで解けそうな問題さがして稼いどいたほうがいいかな? -> あれ、A-large合ってれば大丈夫そう。このままCがんばろう
  • 下記の解法のまま時間切れ。不正解。
  • #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    string solve(string A, string B) {
        // A/B:twitter -> A'/B': TwitteR
        string A_dash = A;
        A_dash[0] = toupper(A_dash[0]);
        A_dash[A_dash.size()-1] = toupper(A_dash[A_dash.size()-1]);
        string B_dash = B;
        B_dash[0] = toupper(B_dash[0]);
        B_dash[B_dash.size()-1] = toupper(B_dash[B_dash.size()-1]);
    
        // しゃくとり法でA'の部分文字列を取り出して、B'の部分文字列になっていないものを探す
        int head = 0;
        int tail = 0;
        int curAstahNam = 0;
        string curPattern = A_dash;
        while(tail < A_dash.size()) {
            string subsec(A_dash, head, tail-head+1); // subsec: subsequence of A
            if (B_dash.find(subsec) == string::npos) {
                // pattern: *aaa* みたいな最終的な識別パターン。
                string pattern = (head == 0 ? "" : "*") + subsec + (tail == A.size()-1 ? "" : "*");
                for (int i = 0; i < pattern.size(); i++) pattern[i] = tolower(pattern[i]);
                int astahNum = (head == 0 ? 0 : 1) + (tail == A.size()-1 ? 0 : 1);
                string prevResult = curPattern;
                // patternを、問題の優先順位に従って更新
                if (pattern.size() < curPattern.size() ||
                        (pattern.size() == curPattern.size() && astahNum < curAstahNam) ||
                        (pattern.size() == curPattern.size() && astahNum == curAstahNam && pattern < curPattern)) {
                    curPattern = pattern;
                    curAstahNam = astahNum;
                }
                head++;
            } else {
                tail++;
            }
        }
        return curPattern;
    }
    
    int main() {
        int T; cin >> T;
        string A, B;
        for (int i = 1; i <= T; i++) {
            cin >> A >> B;
            string answer = solve(A, B);
    
            cout << "Case #" << i << ": " << answer << endl;
        }
    }
    

反省

  • ワイルドカードは空文字を含むって部分を読んでなかった。その時点で正解する可能性は無かった。問題はちゃんと読もう。おちつけ。
  • しゃくとり法がやりたくて飛びついてしまった感。そもそも、50文字までなら部分文字列も総当たりできた。ちゃんと問題のサイズを見て考えられるアルゴリズムを検討するべき。おちつけ。
  • a*cみたいに文字の間にワイルドカードが入るケースをなんとなくで簡単に切り捨ててた。おちつけ。
  • D,E読んでないのもいくなかった。せっかく日本語なんだから、点とれたかわからないけどとりあえず全部読んで、総当たりでSmall解けそうかぐらいは考えてみるべきだった。

予選、決勝と楽しかった!今回で競技プログラミングやる人増えたはずだし、また日本語のCodeJamやって欲しいな。スキルと落ち着きを身につけて次回はもっといい順位とりたい。チャレンジブックとGCJ過去問とTopCoderで鍛えよう

ありがとう スティーブ・ジョブズ

そんなに心酔してた自覚はなかったんだけど。

今日は朝iPhoneでニュースを見てから、なんか未来が失われたみたいな喪失感でぼーっとしてた。僕がまだ知らないイノベーションに満ちた未来はジョブズの頭の中には既に存在してると思ってたのかな。

あとに続く感情はただただ感謝。Appleの製品は僕の生活を変え、ワクワクを提供し続けてくれた。僕も、ものづくりに関わるエンジニアとして、使ってくれた人からありがとうって言ってもらえるものを作りたいと強く思いました。

今日買ったMacBook Air、上手に使っていいものを作ります。
ありがとう。

自宅サーバをシャットダウン

Amazonの東京データセンターが開設された時からやろうやろうとは思ってたんだけど、ようやくAmazon EC2/S3に乗り換えて自宅サーバをシャットダウンしました。

USにしかデータセンター無かった頃は、SSHでちょっと入ってみてレスポンスが悪すぎて「これはないわ…」って思ってたんだけど、さすがに東京だとほとんど家に置いてあるサーバと変わらない。
多分月4000円くらいの負担にはなるんだけど、45Wの自宅サーバもそれはそれで電気代月500円以上かかってたはずだし、データの多重化とかハードの修理サポート代金と思えば差額もどうということはないかと。AWSは使い慣れときたいし、ハードウェアリソースをAPI経由で得られるのはほんとに便利。GDDのスライドパズルを一時的に100インスタンスくらい立ち上げて力技で解いてみたいとか妄想膨らむ。

自宅サーバは2TのHDD積んどきながら全く使わなかったので、余生はたまに起動してファイルをバックアップするお仕事をしてもらいます。