MinBy

        var minBy = list.Aggregate((a, b) => a.Age < b.Age ? a : b);
        Console.WriteLine(minBy);

お題はGroupBy、OrderByを使ってみる - waりとnaはてな日記のもの。ただの例題だと思うので(例だとGroupByを使う意味がないし)突っ込むとかそういうつもりはなく、そういえばRubyでいうmin_byってないなあ、と思ったので。Aggregateはとても素敵メソッドだと思うけど、いざ使おうと思うとあまり使うシーンがなくてとても悲しい。

ver 1.3.0.4 動かなくなったのでちょっと書き換えた

昨日の朝だか昼だかから動かなくなってたっぽいので、それを直しました。何で動かなかったのかよく分かってないんですが、ダメになった箇所だけは分かったので別のアプローチで、ということで。応急処置もいいとこで、まー情けないのですが、動けばいっか、ってことで。眠いし。ダメですかダメですねすみません。

今後だと、一応ダッシュボードのアップデートが8月に控えているらしいので、それでも引っかかってダメになるかもしれませんが、ダメっぽくなったのを捕捉次第、速やかに直したいとは思っているのでダラダラとお待ちください。

LinqとCountの効率

IEnumerableを受け取ってのReverse(), Count(), ElementAt(), Last()は普通に考えると先頭から舐めるので効率がよろしくない。じゃあLinqの実装はどうなってるかというとSystem.Core.dllを眺めると

// Reverse
ICollection<TElement> is2 = source as ICollection<TElement>;
// ElementAt
IList<TSource> list = source as IList<TSource>;
// Count
ICollection<TSource> is2 = source as ICollection<TSource>;
// Last
IList<TSource> list = source as IList<TSource>;

というわけで、IListを実装しているものなら、ちゃんと変換してくれているので大丈夫。Count()なんかは普通にLength/Countを使うから別にどうでもいいって話なのですが、Last()は[hoge.Length - 1]って書くのは嫌なので、こうして安心して使えると嬉しい話。まあ、こんなことは過去何回も話題に上っているのですが、一応自分で確認しておかないとね、ということで。

MSDNのCountの説明にはICollectionを実装してるとそれ使う、って書いてあるけど、Lastのページには何も書いていなくて困ります。内部でisだのasだのやってゴニョゴニョしてるのなら、そのことも全部記載して欲しいなあ。

といったことを何故突然というと、C#にもほしい ~rubyのeach_with_index~ - SEの勉強日記という記事を見かけたので。Count()のうえにElementAt()のラッシュというのは、IListだけならいいんですけどIEnumerableで拡張メソッドを作っているので、少しよろしくない。

public static class Extension
{
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
        {
            action(item);
        }
    }

    public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
    {
        var index = 0;
        foreach (var item in source)
        {
            action(item, index++);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Enumerable.Range(5, 6).ForEach((item, index) =>
            Console.WriteLine("item={0} index={1}", item, index));
    }
}

という風にしたほうがいいと思われます。まあ、あと、new List()なんてやるぐらいなら.ToList()かしらん。

ver 1.3.0.3 / ちょっとした拡張メソッド群

Gears of War 2やCall of Duty : World at Warでステータスが取得出来なかった件を修正しました。GoW2は修正を確認出来ましたがCoD:WaWは持ってないので分からない。多分直ってると思うけど。あと、この修正の影響で他がダメになる可能性がなくもないです。ダメっぽいのを発見したら即直す、という方向で暴走さえしなければある程度はいっかー、的にゆるふわ気分でいるのですがダメでしょうかダメですね。

ところで、int.Parseが多くなって結構面倒くさいので文字列に拡張メソッド。

public static int ToInt(this string value)
{
    return int.Parse(value);
}

public static int ToIntOrDefault(this string value)
{
    int result;
    int.TryParse(value, out result);
    return result;
}

public static string Remove(this string input, string pattern)
{
    return Regex.Replace(input, pattern, "");
}

public static Match Match(this string input, string pattern)
{
    return Regex.Match(input, pattern);
}

public static string Replace(this string input, string pattern, MatchEvaluator evaluator)
{
    return Regex.Replace(input, pattern, evaluator);
}

RemoveとReplaceは既存のメソッド名のものに足してるので、別の名前のほうが良いかしらん。あと、Replaceは引数が被るので、ただの文字列置換は用意できなかった。まあ、_ => "hogehoge" といった具合に「_ => 」が増えるだけならそう手間でもないような十二分に手間のような。

totalGamerScore = document
    .Descendants("div")
    .First(e => e.GetAttribute("className") == "XbcProfileSubHead")
    .Descendants("strong")
    .Last()
    .InnerText
    .Match(@":\s*(\d+)/")
    .Groups[1]
    .Value
    .ToInt();

こんな風に書けます。これでスクレイピングも快適ー。ドット繋げまくれてバンザイしちゃう。ただまあ、デバッグはし辛いですね。ログ吐くメソッドを仕込んだりもいいんですが、もっと単純に、ラムダ式挟めばデバッガで止められるので

public static class Ext
{
    public static TResult Tap<T, TResult>(this T self, Func<T, TResult> func)
    {
        return func(self);
    }

    public static T Tap<T>(this T self, Action<T> action)
    {
        action(self);
        return self;
    }
}

RubyのTapみたいな、ということで。

ダミー置いて、その場で止められるようになる。それで作って、出来あがったらTapの行をCtrl+Xでゴミ箱ぽい。IEnumerableの場合は、普通にダミーのSelect置けばいいだけでしたね! 今、そのことに気付いた。うーん、あと.Groups.Cast<Group>().Skip(1).Select(g => g.Value) も、頻繁にあるあるなので、Matchに拡張メソッド埋めときますか。

ver 1.3.0.2 色々バグ修正

バグフィックス祭り! まずバグ報告があってそれを直して、つまりは普段と少し違う状態の時の処理が全く入ってなかったので、洗い出して処理を入れました。別に全く考えていなかったわけじゃないのですが、想定からの漏れが幾つか、というかたっぷりありまして……。具体的には「申請待ちのフレンドがいるとエラーになる」「ステータスが「退席中」の際にデータが正しく取得出来ない」「ステータスが「取り込み中」の際にエラーになる」です。不具合くせえええ、と思ったら遠慮無く言っていただけるととっても助かりますので、お願いします。

ver 1.3.0.1(XboxInfoTwit) / exception(アーケード)

全てのゲームタイトルで、オンラインマッチ時にステータスが途中参加可能な状態で実績取得が出来ず、タイトル名がおかしくなる件を修正しました。Xbox.comから文字列決めうちで切り出しているので、どんな文言が来るのかのパターンに漏れがありましたというか知らんかった……。(ちなみに現在、待機中でも同様の問題があったりするので、直します、次回に、他にもないかちゃんと調べてから)。こうしてバグ発覚な上に(しかもこの問題は以前からあったっぽいです、全然気づいてなかった)、自信満々に互換性向上!とか言っておきながら、動かなかったって人がいるみたいでごめんなさい。しかも以前のバージョンでは動いていたとなると、もう本当にごめんなさい……。

//

ところで話かわって、exceptionのアーケード版がロケテされてるらしい、新宿南口ワールドで7/9~15だそうだ。というわけで行ってきましたは二日目。実は初日にも行ったんですが、お上りさんなので間違えて東口のタイトーステーションに行って、置いてないなあ、と思ってた。いや、「タイトーステーション 新宿南口ゲームワールド店」自体には何度か行ったことはあるんですよ!でも、タイトーって印象がないというか真面目にセガだと思ってた(笑) 別に西口のセガのと思い違いしてたわけでもなく素で。それで、東口のほうにはインベーダー(=タイトー)の印象があったので、ほぅほぅ、あんなところも南口に含めるのか、とか思ってたとか思ってたとか。悲しい。ゲーセンの店名って意識したことないのよね、あまり行かない人なので。

アーケード版のゲーム内容ですが、普通にexceptionでした。ステージは若干アレンジされていたり、オリジナルステージがあったりなどですが、内容は全くそのままPC版のexception。処理落ちなどもなく、ヌルヌルと動いておりました。ただし破片量はノーマルか、それより少ないか、といった感じで若干の寂しさは否めない。

気になる操作方法はジョイスティックとボタン3つ。全方位STGでスティック一本ということで、ボタン一つが方向 転換用の固定ボタン(PC版のディレクション)に割り当てられていて、これがぶっちゃけ操作しづらい。残りのボタンはレーザーとレイ、二つを(一度離して)同時押しでカタパルト。このカタパルト動作が筋力貧弱な私には存外辛くて、終わり頃には腕が疲れちゃってた。カタパルト→カタパルト→カタパルトと連打するわけなので、ワンボタンで出したいなあ、と思いつつも、まあボタンあまってないししょうがないね。

そんなこんなだから、というわけじゃないのですが、あえなくPC版3面ボス(アーケードでは5面、だったかな?)で死亡してスコアは5位でした。ランキング一位は、PC版作者のi-saint氏のよう。i-saint氏が初見で?クリアしたようなので、なら私も!とか意気込んでいたのですがズタボロ。いてれーたんに普通にいいように弄ばれるという微笑ましさを見せつけました。

ステージ構成はPC 版->アーケードオリジナル->PC版……と交互のようです。PC版は若干短く簡素にアレンジ。アーケードオリジナルのほうは破片の少なさを補うためにギミック中心の構造になっていて新鮮で面白い。ボスも同様に飛び道具系、というか変形する。アーケードオリジナルボス2体目の倒し方が分からなかくてライフが半分減るまで無意味なことやってたり。新鮮なのはよいことです。

全体的には、昔のアーケード→ファミコン移植のような印象。おお、頑張ってる!という。破片量はしょうがないとしても、操作し辛いのはどうしたものかなー。今回私は3ボタン使う上級者向け操作を選んだので、2ボタン操作の初心者向け操作だと印象違うかもしれません。そういえば、エフェクトも弱めなのでカタパルトの爽快感が薄かったような気がする。回りを破片で囲まれてピンチをカタパルトで一気に突破!的なのが、画面が真っ白になって抜け出せたのか何なのかわけわからないというか自機が本当に白に埋まって見失う、のはどうなのだろう、慣れかな?ジオメトリとかも見失うって言われるわけだし。

とはいえ普通にexceptionだったので普通に面白いと思います。オリジナル面も良い感じだし。PC版に比べてどうよ?と言われると完全にノーコメント(すみません)ですけど、ジョイスティックでやるのも新鮮、ということで遊びに行ける人は遊びに行くと良いやも。とりあえず私は途中で死亡したのが悔しいので、明日も行きます、というかロケテ中にはクリアしたい。(それにしても音楽も効果音も全く聞こえなかった、周囲の音うるさすぎ、私はひなびた田舎のゲーセンが好きですよ(笑))

あと、せっかくなので明後日、7/12の日曜日の22:00頃からUstreamでexceptionとexception conflictを実況プレイしようと思うので良ければ見てやってください。

ver 1.3.0.0 ロジック変更/OAuth対応

公開から半年以上経って、何故かここ数週間で利用者が増えてきたようで同時に動かない報告も目にするようになって嬉しくも悲しい。なので、今回ロジック部分を完全に書き換えました。これで色々な環境でも動作するようになった、はず、です。以前に試して動かなかったという方は、再度試していただけると嬉しいです。ついでに取得処理も軽量化しました。真面目に10倍ぐらいは速くなってます(今までが酷過ぎただけなんだけどね!)。そんなこんなで手を入れた部分が多いので、(ただでさえ不安定との定評があったのに)安定性はむしろ下がった、かも……。

それと、認証がパスワード方式からOAuth方式に変更になりました。ユーザーにとってOAuth対応によるメリットは、クライアントアプリではぶっちゃけ別にないどころかむしろ色々な不都合のほうが多いのですが私がやりたかった、ということで勘弁してください。投稿にfrom XboxInfoTwitってクライアント名が表示されるようになって嬉しいのです、にひひ。自動アップデート経由の方は、認証を一度済ませなければならないので手間です、すみません。

あ、で、ver1.2からそうなのですが、現在はAPIは一切利用していませんので遅延はありません。Xbox.comのステータス反映速度(1分以下で追随しているようです)で処理していますので、原理的には他の同種のアプリと同じです。が、多機能風味なため、巡回ページ数が多いのでチンタラ通信してたりする時があって、そのせいで反映が遅いという印象を持たれるかもしれません。今回の軽量化で若干印象は変わると思いますがそんなに変わらないかもしれません。その他、投稿の法則やFAQは同梱の説明書きを見てください。

↑通信内容はこんな感じです(Fiddlerで観測)。30秒かかりました。結構長いけれど、Xbox.comが重いサイトだからねえ……。まずフレンドリストの取得、そこからフレンドのフレンドに飛んで自分のステータスを取得(取得できない場合は取得出来るまで次のフレンドに飛ぶ)、トップページに飛んでプレイ中ゲームのURLを取得、プレイ中ゲームのページから実績を取得。という流れです。これがステータス取得の最短パスじゃないかと思っています。自分のステータスがFriendsOfFriend経由でしか見れないというのが意味不明で困るところ。

そういえばでどうでもいいんですが、タスクバー右クリックに「ゲイツポイントを買う」が追加されてます。アフィです、アフィ。んーと、ノーコメント。

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(.NET)
April 2011
|
July 2025

X:@neuecc GitHub:neuecc

Archive