2013年10月28日月曜日

シミュレーター(コンソール版)



この間のWindowsForm版の奴はあまりにも計算速度が遅いし、自分のコードがわけわからなくなったので(こっちがメインの理由)もっかい下地から作りなおして

・リーグ、チーム、プレイヤーの数を自由にユーザーが作成可能
・1チームだけだと試合と言えないので2チームで試合を可能
・誰が出塁しているのかを保存してランナーの個性をつける
・試合結果を年度ごとに保存してそのサマリーを書き出せる
・シミュレータのベースとなってるのはBattingRunsという考え方なのですが、その係数をいじっていろいろな条件でシミュレータを動かす
・一軍登録、二軍登録を作る

という機能を加えてみました。コンソールだけど。
その結果クラスがめちゃくちゃ大量に発生してしまって管理が大変です…
オブジェクト指向の設計の方法とかいう本をちょいちょい読みながら作ってるんですが、クラスの量が大量になってくるとオブジェクト指向の良さが生きてくる感じがします。
最初の頃に比べてだいぶC#の用語(メソッドとかプロパティとか)の意味もだいぶつかめてきました。C#の技術本読んだだけで理解したつもりになってたのが作ってる途中でどんどんわかってきて、前自分が書いたコードが汚くみえて書き直すことばっかりです。なんかこうやっていろいろわかっていくのが実感できるのは楽しいです。
これからオブジェクト指向も勉強しないといけないですね。

2013年10月24日木曜日

C#でデータベースを作る

野球シミュレーターで計算した値を何処かに保存しとくのに、いちいちCSVファイルで出力するの面倒臭いし毎回読み込まないといけないし…って悩んでいたんですが、いちいち書き込むんじゃなくデータベースを使えばええんでは?という助言をもらったので試すことに

まず、そもそもの問題としてデータベースが何者なのか全くわかってない(もちろん作り方も全くわからない)上にどうやってアクセスをすればよいのかもわからず、Googleにいろんな検索ワードをぶち込みながら色々なページを読みかじってましたが、数年前のちょっと古い記事がヒットすることも多くて今の自分の環境(VisualStudio2012)でも動くのかわからないし、やたらと僕からすると高度な内容がつらつら続いてて読むのが辛かったりとだいぶ時間をロストしました

おぼろげに

・SQL?とかいう形式でやりとりをするらしい
・データベースにアクセスするやり方(ライブラリ?)がいろいろあるらしい
・どうやらデータベースをサーバーに置いてそれにアクセスすることもできるらしい

とかいうことはわかったような気がしてるんですが、めっちゃとんちんかんなこと言ってる気がしてならないです(間違ってたらごめんなさい)
でまあ最終的にこの記事にあるSQLAerverCompactというのを使うことにしました。Microsoftがタダでくばってるアクセス用のライブラリらしいですね、Microsoft素晴らしい
http://hoshii-mono.com/features/subcategory-16.php

これで今のところうまく通信出来てるみたいなのでコイツ使いながらやってきたいと思います

2013年10月21日月曜日

C#で打線シミュレーターを作る

前にシミュレーターを作りかけで投げ出してたんですが、今度はWindowを出して普通のソフトっぽく動かせるようなやつを作ってみようかなと思いたって、ここ2日ぐらいこないだ作ってたコンソールアプリを流用しながら、Windowsフォームを使って(ようするに普通のソフトみたいな外観で)ユーザーがスタメンの選手とか選手の成績とかの設定をいじって、その時の打線の様子をシミュレートできるもんを作ってました。

スクリーンショットはこんな感じ。なんか適当に配置していたらやたらと横長になってしまいました



元々のシミュレーターは、プログラムの中身に誰をスタメンにするのかとかその選手がどのぐらい打てるのかっていう情報を埋め込まないといけないちょっと不便なものだったので追加の機能として

・今読み込まれている選手データを表示してその成績を表示する
・ユーザーが新しい選手データを登録できる
・スターティングメンバーを選手データから選択して配置する
・シミュレーター本体の処理がめっちゃ重いので、今どのぐらい処理が終わっているかを見れるようにする

をできるようにしました。
といっても、読み込むデータに制限が多すぎたりちょっと不便なことも多いので改良しなくちゃいけないことも多いので、もうちょっと柔軟性をもたせたプログラムに変更していかないと、っていう状態です。

それにまだ外部からCSVで選手データを読み込んだり、シミュレーターを動かした結果を保存したりとか、結果をグラフでわかりやすく(できればかっこよく)表示する、みたいな基本的な機能もできていないので当分はそれを実装するのを目標にちょいちょい改良できればなぁと思ってます。

2013年10月14日月曜日

遂に

カープが遂にAクラス&CSファーストステージ全勝通過!素晴らしきことです

CSファイナル二戦目のチケットを運良く手に入れることができてたのでもしかしたらカープ戦が見れるかも…とは思ってましたがまさか本当に来るとは!

張り切って応援してきたいと思います!このまま日本一行ってしまえ!

2013年9月4日水曜日

距離感

2週間ほどの帰省からの帰還.終わってみると案外あっけないような長かったような不思議な二週間でありました。勝手にご飯が用意され掃除が行き届くという天国の様な環境に甘えた結果、体重がえらいことになっている以外は久々の地元の空気がなかなか新鮮で楽しく過ごせました。

長いこと会えていなかった高3の担任が寂しがってるという情報をキャッチしていたので母校へ行ったのですが,なんだか周りがわっかい高校生中学生ばかりで(当たり前)、ちょっと前までこの空間に自分が居たことが信じられませんでした。あの空気に僕はもう馴染めません。完全アウェーです。

帰りに寄った部活でマウンドに久々に経った時もホームとの距離がやたらと遠くて、数年前はここで平気で投げていた事が実感を伴って思い出せず、ちょっとさみしい思いをしました。

よく久しぶりに会う友達にも変わってないなぁと言われる事が多かったり、自分でも高校から大学にかけて対して変わっていないつもりではあるにしても、ちょっとづつ変わっているようです。

ちなみに担任は一ミリも全く変わっておらず、「なんで来たんだなんか精神でも病んでるのか? そうじゃないなら早く東京で彼女でも作れ、とりあえずはサークルだサークルに入れそして遊べこんな田舎から早く帰れ」とありがたい助言を頂きました。彼はあのままで死ぬまで突き通してほしいです。

2013年8月16日金曜日

打線シュミレーターを作ろうとする

using System;
class Player
{
    public string name;
    public int pa, ab, hit, single, two, three, hr, bb;
    public double avg, obp, slg, ops;

    public void data(string name, int pa, int hit, int two, int three, int hr, int bb)
    {
        this.name = name;
        this.pa = pa;
        this.ab = pa - bb;
        this.hit = hit;
        this.single = hit-two-three-hr;
        this.two = two;
        this.three = three;
        this.hr = hr;
        this.bb = bb;
        this.avg = (double)(single + two + three + hr) / this.ab;
        this.obp = (double)(hit + bb) / this.pa;
        this.slg = (double)(single + two * 2 + three * 3 + hr * 4) / this.ab;
        this.ops = this.obp + this.slg;
        Console.Write("Name: {0}, Avg: {1}, OBP: {2}, SLG: {3}, OPS: {4}\n", this.name, (avg).ToString("#.###"), (obp).ToString("#.###"), (slg).ToString("#.###"),(ops).ToString("#.###"));
    }

    public void data(){
        Console.Write("Name: {0}, Avg: {1}, OBP: {2}, SLG: {3}, OPS: {4}\n", this.name, (this.avg).ToString("#.###"), (this.obp).ToString("#.###"), (this.slg).ToString("#.###"),(this.ops).ToString("#.###"));
    }
}

class StartingMenber : Player
{
    public int l_pa, l_ab, l_hit, l_single, l_two, l_three, l_hr, l_bb, l_daten;
    public double l_avg,l_obp,l_slg,l_ops;

    public StartingMenber()
    {
        this.l_pa = 0;
        this.l_ab = 0;
        this.l_hit = 0;
        this.l_single= 0;
        this.l_two = 0;
        this.l_hr = 0;
        this.l_bb = 0;
        this.l_three = 0;
        this.l_daten = 0;
    }
    public void ShowLogData()
    {
        this.l_ab = this.l_pa - this.l_bb;
        this.l_avg = (double)(this.l_single + this.l_two + this.l_three + this.l_hr) / this.l_ab;
        this.l_obp = (double)(this.l_single + this.l_two + this.l_three + this.l_hr + this.l_bb) / this.l_pa;
        this.l_slg = (double)(this.l_single + this.l_two * 2 + this.l_three * 3 + this.l_hr * 4) / this.l_ab;
        this.l_ops = this.l_obp + this.l_slg;
        Console.Write("Name: {0:0.000}, Avg: {1}, OBP: {2}, SLG: {3}, OPS: {4} 打点: {5}\n", this.name, (this.l_avg).ToString("#.###"), (this.l_obp).ToString("#.###"), (this.l_slg).ToString("#.###"), (this.l_ops).ToString("#.###"),this.l_daten);
    }
     
}

class Baseball
{
    public static int[] baseph = { 0, 0, 0, 0 };
    public static int outcount = 0;
    public static int gamenum = 200;
    public static bool kai = true;
    static void Main()
    {
        Player kikuchi = new Player();
        kikuchi.data("廣瀬", 252, 62, 8, 1, 7, 41);
        Console.Write("試合数を入力してください :");
        gamenum = int.Parse(Console.ReadLine());
     
        StartingMenber[] team1 = new StartingMenber[9];
        for (int i = 0; i < 9; i++)
        {
            team1[i] = new StartingMenber();
            Console.Write("{0}番", i + 1);
            team1[i].data("廣瀬", 252, 62, 8, 1, 7, 41);
        }
        int seed = Environment.TickCount;
        for (int k = 0; k < gamenum; k++)
        {
            outcount = 0;
            seed +=2;
            for (int num = 0; outcount < 27; num++)
            {
                if (kai)
                {
                    Console.Write("{0}回の攻撃\n", outcount / 3 + 1);
                    kai = false;
                }
                getdageki(ref team1[num % 9], ref baseph, seed++);
            }
        }
        Console.Write("得点:{0} 平均得点{1}\n", baseph[3], ((double)baseph[3] / gamenum).ToString("#.000"));
        for (int i = 0; i < 9; i++)
        {
            team1[i].ShowLogData();
        }
     
    }

    public static void getdageki(ref StartingMenber batter, ref int[] b, int seed)
    {
        Random r = new Random(seed);
        int d_kekka = r.Next(batter.pa);
        int t = 0;
        batter.l_pa++;
        if (d_kekka <= batter.bb)
        {
            Console.Write("フォアボール\n");
            batter.l_bb++;
            if(b[0]==0){
                b[0] = 1;
            }
            else if (b[1] == 0)
            {
                b[1] = 1;
            }
            else if (b[2] == 0)
            {
                b[2] = 1;
            }
            else
            {
                t++;
            }
        }
        else if (d_kekka <= batter.bb + batter.hr)
        {
            Console.Write("ホームラン!\n");
            batter.l_hr++;
            t += b[0] + b[1] + b[2] + 1;
            for (int k = 0; k < 3; k++)
            {
                b[k] = 0;
            }
        }
        else if (d_kekka <= batter.bb + batter.hr + batter.three)
        {
            Console.Write("スリーベース!\n");
            batter.l_three++;
            t += b[0] + b[1] + b[2];
            b[0] = 0;
            b[1] = 0;
            b[2] = 1;
        }
        else if (d_kekka <= batter.bb + batter.hr + batter.three + batter.two)
        {
            Console.Write("ツーベス\n");
            batter.l_two++;
            t += b[1] + b[2];
            if (b[0] == 0)
            {
                b[1] = 1;
                b[2] = 0;
                b[0] = 0;
            }
            else if (b[0] == 1)
            {
                b[2] = 1;
                b[1] = 1;
                b[0] = 0;
                int rand2 = r.Next(100);
                if (outcount % 3 == 0 && rand2 <= 15)
                {
                    t++;
                    b[2] = 0;
                }
                else if (outcount % 3 == 1 && rand2 <= 25)
                {
                    t++;
                    b[2] = 0;
                }
                else if (outcount % 3 == 2 && rand2 <= 50)
                {
                    t++;
                    b[2] = 0;
                }
            }
        }
        else if (d_kekka <= batter.bb + batter.hit)
        {
            Console.Write("ヒット\n");
            batter.l_single++;
            t += b[2];
            b[2] = b[1];
            b[1] = b[0];
            b[0] = 1;
            int rand1 = r.Next(100);
            if (b[2] == 1)
            {
                if (outcount % 3 == 0 && rand1 <= 30)
                {
                    t++;
                    b[2] = 0;
                }
                else if (outcount % 3 == 1 && rand1 <= 50)
                {
                    t++;
                    b[2] = 0;
                }
                else if (outcount % 3 == 2 && rand1 <= 70)
                {
                    t++;
                    b[2] = 0;
                }
            }
            else if (b[1] == 1 && b[2] == 0 && rand1 <= 20)
            {
                b[2] = 1;
                b[1] = 0;
            }
        }
        else
        {
            outcount++;
            Console.Write("凡打\n");
            if (outcount % 3 == 0)
            {
                if (outcount != 27)
                {
                    Console.Write("チェンジ\n");
                    Console.Write("{0}回の攻撃\n", outcount / 3 + 1);
                }
                else { Console.Write("GameSet\n"); }
                b[0] = b[1] = b[2] = 0;
            }
            else if (b[2] == 1 && r.Next(100) >= 50)
            {
                t++;
                b[2] = 0;
            }
            else if (b[2] == 0 && b[1] == 1 && r.Next(100) <= 25)
            {
                b[2] = 1;
                b[1] = 0;
            }
            else if (b[1] == 0 && b[0] == 1 && r.Next(100) < 5)
            {
                b[1] = 1;
                b[0] = 0;
            }
        }
        tokuten(ref b[3], ref batter.l_daten, t);
    }

    public static void tokuten(ref int g_tokuten, ref int b_daten, int t)
    {
        g_tokuten += t;
        b_daten += t;
        if (t > 0)
        {
            Console.Write("{0}点得点!\n", t);
        }
    }
}

なんかいやってもゴミ2割打者廣瀬と3割後半神廣瀬が交互に並ぶ打線になってシュミレーターの意味を成さない!
おそらくrandomつくってるところがおかしいんだけど,何がおかしいのかさっぱりわからないから困ったぞ~

2013年8月11日日曜日

WHIPの扱い

WHIPの解釈と応用
http://baseballconcrete.web.fc2.com/alacarte/whip.html

最近良く聞くWHIP,あんまり有用じゃないっていうのを何処かで見たような気がしてたんだけど多分これですね.
めっちゃ綺麗にまとめられてる上に論理的ですっきり頭に入るのが良い.実験レポートでもこんな綺麗な文章書きたいね.
これを読んでると,野球の指標って人によって分かりやすさと正確さとどっちを求めるかが違うっていうのをちゃんと頭に入れて考えないといけないなって思う.
複雑すぎても一部のマニアックな人しかわからないし,かと言って打率とか出塁率,防御率みたいな簡単な指標だけで選手のすべてを判断できるかって言うとそうでもないし,正解は無いのかも.