プログラミング

    Railsはちょっとお休みしてRubyを学んでいこう!

    PAYDAY2 Blacklist Assist

    最近更新中のPAYDAY2のBlacklist MODの補助ツール
    ※特に理由が無い場合は最新バージョンを使用してください。


    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    Rails難しくてあきたとかじゃな・・・ちょっとね。

    やはりRailsを学ぶにはRubyをおさえなくては!!(Rubyの本読んだだけで結局Rubyのプログラム書いてなかった)

    ということで、昔買った「Javaゲームプログラミングアルゴリズム」を引っ張り出してきた。

    中学生のころにこの本を買ってもらったものの、Javaのよく言われる「おまじない」に納得いかない、意味が分からなくて投げたことを思い出した。

    なのになぜC#をわりかしすんなり呑み込めたのだろうか・・・謎である。

    今思えばC#もおまじない系だと思うのだが・・・なぜか、そしていまJavaの本を読むとなぜ分からなかったのか分からない・・。

    何はともあれ、この本の最初に出てくるレースゲームもどきをRubyで書いてみた。

    一応できたものの、うーん。

    170408_Race1.png

    思っていたものと違う。

    そもそも、Rubyで書くべきではなかった。(今更)

    どうしても入力待ちが発生してしまう(スレッドはあきらめた)

    入力待ちになるため、考える時間がいくらでもあり、まー死なない。

    次はリアルタイム性の要求されない、ターン制のものを作ろう!

    初めてのRuby書いた学び!


    ・-- ++は使えない! += -=を使おう!
    ・偶数奇数の判定は % 2よりも even?を使うといいぽい!?(型の問題なのかな?%2だとうまくいかなかった)
    ・インスタンスメソッドとクラスメソッドの違いがよくわからないー


    一応ソースコードもあるよ。
    https://bitbucket.org/rinjugatla/race
    スポンサーサイト

    考えたことがあたってるとちょっとうれしくなるよね

    PAYDAY2 Blacklist Assist

    最近更新中のPAYDAY2のBlacklist MODの補助ツール
    ※特に理由が無い場合は最新バージョンを使用してください。


    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    ちょうど一年前くらいにとある理由でプログラムを書くことになった。

    ・読み込むデータは用意されている
    ・解析手法も用意されている
    ・結果の見せ方も大体既存の参考資料がある

    ・使用言語は自由
    ・とりあえず動けばいいらしい

    というゆるい開発だったので、これまでの趣味の延長で作り始めた。

    やはりGUIはあったほうが便利だろうということ、グラフや表で結果を示したかったこともあり、言語はC#を選んだ。
    (というより割とまともに扱えるものがC#以外にな・・・)

    読み込むデータは大体以下のようになっていた

    data.csv
    #ヘッダー開始(ない場合もあり、ない場合はヘッダー終わりもなし)
    #ヘッダー終わり
    日時,データ1-1,データ2-1,...(複数列)
    日時,データ1-2,データ2-2,...
    日時,データ1-3,データ2-3,...
    以下数千から数百万行

    ・解析手法でのちにデータを消すことが分かっている
    ・とりあえず動けばいいらしい

    ということから、今までの経験から得た技術のListを用いてデータを格納していることにした。

    Step0
    List1-1(データ1-1を格納)
    List1-2(データ1-2)
    List1-3(データ1-3)
    List1-4(データ1-4)
    List1-5(データ1-5)

    と順番に格納していくわけである。(データ2-は表記省略)

    解析する間に

    Step1
    List1-1(データ1-1)
    List1-2(データ1-2)
    List1-3(データ1-3)

    List1-4(データ1-5)

    Step1
    List1-1(データ1-1)

    List1-2(データ1-3)

    List1-3(データ1-5)

    と歯抜けになっていく。

    Forで回していたと思うので、ここはList.RemoveAt(Int32)でデータを抜いていった。

    しかし、遅い、遅い、待てども待てども終わらない。何が悪い?

    既存技術の組み合わせということがあって、同様の処理をするプログラムがフリーで公開されている。
    それらを用いると時間がかかるものでも1分程度、自作のものは1時間以上かかる。

    明らかにおかしい!
    いろいろな場所にブレークポイントを設置した結果、上記の箇所が原因であると特定された。
    (ここまでに一通り作ろうと思っていた機能をすべて盛り込み済みで、自分の開発した中では最大規模のプログラムになっており、特定作業も大変であった)

    どうやら、要素を削除するたびに、要素を前に詰めているようだった。
    言葉にすると伝わりづらいだろうか、昔作った画像が出てきたので参考に

    270407_prog.png

    数百万*数列あるデータに対して、列ごとにデータを一つ消すたびに後ろからデータを詰めていたらしく、計算量は莫大な量になっていたということである。

    今までは扱うデータ量が多くとも数千程度だったので、詰め詰めしても大して気にならなかったようだが、今回は数百万*十数と今までとは全く違う規模のデータ量なので問題が浮き彫りになった。

    消すとダメ・・・ダメ・・・なら飛ばせばいいじゃない!とひらめいた。
    お風呂に入っていた時だったような気がする。ぽけーっとしてるとひらめくことあるよね。

    270407_prog2.png

    要素を作成する際に、前後関係と要素データを合わせて持つようにする。

    Step0
    List1-1(データ1-1を格納、前なし、後1-2)
    List1-2(データ1-2、前1-1、後1-3)
    List1-3(データ1-3、前1-2、後1-4)
    List1-4(データ1-4、前1-3、後1-5)
    List1-5(データ1-5、前1-4、後なし)

    といった具合である。
    すると

    Step1
    List1-1(データ1-1を格納、前なし、後1-2)
    List1-2(データ1-1、前1-1、後1-3)
    List1-3(データ1-2、前1-1、後1-5)
    List1-4(データ1-4、前なし、後なし)
    List1-5(データ1-5、前1-3、後なし)

    といった具合になり、詰め詰めしなくともすむ。
    これは!すごいのでは!

    と、独自でクラスを作り始めたのだが、途中で「もしかして、自分が思いつくのなら既にあるのでは?」と考え、検索してみると

    「連結リスト(片方向リスト、双方向リスト)」

    というものが、これにあたるようで、C#にももちろん標準で実装されていると分かった。

    こちらを利用したところ、ほかのフリーソフト並みの爆速で処理が終わるようになった。
    今度のボトルネックはストレージからの読み込み速度だが、ここはいまだに難儀している。

    何はともあれ、

    「何が悪い?」

    から

    「消すとダメ・・・ダメ・・・なら飛ばせばいいじゃない!とひらめいた。」

    「もしかして、自分が思いつくのなら既にあるのでは?」


    やっとタイトルである、「考えたことがあたってるとちょっとうれしくなるよね」

    先人たちも同じところで躓いて、同じことを考えていたと分かるとうれしい!

    もちろん、そんなところで時間を(完全ではないにせよ)無駄にしないためにも基礎知識をきちんとつけておくべきではある。

    でも、うれしいよね。

    と、なぜ今更こういうことを書いたかというと、先ほども同じ経験をしたからである。

    ・ユーザ登録型
    ・ユーザごとに個人ページを持ち、ブログのようなことができる

    といったものをRailsの勉強で作ろうとしてるのだが、何分データベースもまともに触ったことがないので、データベースをどう作ればいいのかとここ数日悩んでいた。

    初期の想像

    Table ユーザ情報
    ID Name Password など
    1 Taro ababa
    2 Hana gegeg

    Table Taroさんのブログ
    記事ID Title Text など
    1 te fefef
    2 fdf fefe

    Table Hanaさんのブログ
    記事ID Title Text など
    1 te fefef
    2 fdf fefe

    これではユーザが増えるごとにテーブルが増える・・・テーブルが増えるとパフォーマンスが悪いと、ではどうすれば・・・。

    と先ほど思いついたのが

    Table ユーザ情報
    ID Name Password など
    1 Taro ababa
    2 Hana gegeg

    Table ブログ情報
    記事ID 投稿者ID Title Text など
    1 1 fefe cdcd
    2 2 df cece

    ブログ記事情報を一つのテーブルにまとめ、中に投稿者IDを作ればいいのだ!なるほど。

    これが正解らしい。

    と、いうことで、ふと前の経験を思い出したわけである。

    Ruby on Rails 初心者の覚書

    PAYDAY2 Blacklist Assist

    最近更新中のPAYDAY2のBlacklist MODの補助ツール
    ※特に理由が無い場合は最新バージョンを使用してください。


    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    詰まったところやらをつらつら書き連ねていこうかなな記事
    間違ってるかも

    アプリケーションの作成


    rails new アプリケーション名

    例:rails new hoge


    コントロールの作成


    rails g controller コントロール名 生成メソッド

    例:rails g controller top index


    上記でコントロールを作ると
    hoge/controllers/top_controller.rb
    hoge/views/top/index.html.erb
    このままだとルートが存在しない(route.rbにroot 'tops#index'を追記)としてエラーが出るため、ファイル・フォルダ名をそれぞれ変更する
    (手違いで複数形でファイルが生成されなかったのか、なにか作るときの命名規則に従っていなかったのか・・・?)
    hoge/controllers/top_controller.rb -> hoge/controllers/tops_controller.rb
    hoge/views/top/index.html.erb -> hoge/views/tops/index.html.erb

    そもそも複数形の名称でコントロールを作るのが良いようで


    ルートの指定


    hoge/config/ routes.rb
    root 'コントロール名(複数形)#index'

    例:root 'tops#index'


    配列の宣言とアクセス方法

    PAYDAY2 Blacklist Assist

    最近更新中のPAYDAY2のBlacklist MODの補助ツール
    ※特に理由が無い場合は最新バージョンを使用してください。


    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    VBAかじったので忘備録
    数時間いじった程度の知識量

    宣言方法とそれぞれのアクセス方法について例を示しています。
    タイトルのジャグ配列は一番最後です。

    (一次元)配列

    excel_exp_array1.png

    宣言方法1


    Dim x(3) As Variant
    x(0) = "a"
    x(1) = "b"
    x(2) = "c"
    x(3) = "d"

    ※Dim x(i) As Variantで用意されるiは要素数ではなく、要素の添え字なので要素数-1を指定する。

    宣言方法2


    Dim x(0 To 4) As Variant
    x(0) = "a"
    x(1) = "b"
    x(2) = "c"
    x(3) = "d"

    ※Dim x(i To j) As Variantのiは自由に決められる。i=1 j=3とすると、x(1)から3個の要素数を確保する。

    宣言方法3


    Dim x As Variant
    x = Array("a","b","c","d")

    ※動的配列の場合はReDimを使用する

    アクセス方法


    x(1)
    x(3)
    など


    多次元配列

    excel_exp_array.png
    3行4列の二次元配列

    宣言方法1


    Dim x(2,3) As Variant
    x(0,0) = "a"
    x(0,1) = "b"
    ...
    x(2,3) = "i"

    宣言方法2


    Dim x(0 To 3, 0 To 4) As Variant
    初期値の設定方法は宣言方法1と同じなので省略する。

    宣言方法3


    Dim x As Variant
    x = Array(Array("a", "b", "c", "d"), Array("e", ....), .... Array(..., "i"))
    ほぼジャグ配列の考え方、配列の中に配列を宣言する方法。

    ※次元数を増やす場合はDim x(i, j, k ...) As Variant

    アクセス方法1


    宣言方法1,2の場合はこちら
    x(0,0) = "a"
    x(0,1) = "b"
    ...
    x(2,3) = "i"

    宣言方法3の場合はこちら
    x(0)(0) = "a"
    x(i)(j) = k

    ジャグ配列

    excel_exp_jugarray.png

    ジャグ配列は何行何列と言えるのか・・・?
    あえて言うならば3行4列の二次元ジャグ配列

    宣言方法1


    Dim x As Variant
    x = Array(Array("a", "b", "c"), Array("d", "e"), Array("f", "g", "h", "i"))

    宣言方法2(試していないので動作不明)


    事前に配列を複数個宣言しておいて、他の配列に入れるという方法でもよいかもしれない。
    Dim x As Variant
    Dim i As Variant
    i = Array("a", "b", "c")
    Dim j As Variant
    j = Array("d", "e")
    Dim k As Variant
    k = Array("f", "g", "h", "i")
    x = Array(i, j, k)

    アクセス方法


    x(0)(0) = "a"
    x(i)(j) = k


    おまけ


    動的配列の割り当て


    Dim x As Variant
    x = Array("a", "b")

    x(0) -> a
    x(1) -> b

    ReDim x(3)でxの要素数を添え字3個までの4個を確保する
    ただし、注意しなければならないのはこの際これまでの要素をすべて削除し、サイズを変更する点。
    つまり
    x(0) ->
    x(1) ->
    となる。

    要素を引き継ぎつつ、サイズを変更する場合は

    ReDim Preserve x(3)

    とする必要がある。


    要素数を調べる関数


    LBound関数 -> 引数で指定した配列で使用できる最も小さいインデックス番号を返す
    UBound関数 -> 引数で指定した配列で使用できる最も大きいインデックス番号を返す

    使用例
    Dim x As Variant
    x = Array("a","b","c","d")

    LBound(x)とした場合は0
    UBound(x)とした場合は3
    を返す。

    [覚書] C# 非同期処理の例外処理外エラー個所の特定

    PAYDAY2 Blacklist Assist

    最近更新中のPAYDAY2のBlacklist MODの補助ツール
    ※特に理由が無い場合は最新バージョンを使用してください。


    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    最近非同期処理を実装したプログラムを書いているのだが、非同期で例外処理をきちんとしていないとエラーがとても厄介なことになると学んだ。
    この場合のエラー個所の特定方法についての覚書。

    まず、非同期処理内で例外処理(try catch)をしていない場合に表示されるエラーについて。

    非同期処理内、例外処理なし
    タイトル「TargetInvocationExceptionはハンドルされませんでした。」
    追加情報「呼び出しのターゲットが例外をスローしました。」
    rainflow_async_error1.jpg


    非同期処理内、例外処理あり
    try{ /// }catch(Exception ex){ ex.ToString(); } とりあえず例外表示するだけ
    rainflow_async_error2.jpg


    同期処理内、例外処理なし
    タイトル「ArgumentOutOfRangeExceptionはハンドルされませんでした。」
    追加情報「インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。」
    rainflow_async_error3.jpg


    今回引っかかったのは、いろいろといじって、いじりすぎて、いざデバッグを実行したところ、”非同期処理内、例外処理なし”のエラーが表示されたが、いじった個所が多すぎてどこが問題なのかわからなかったことだ。
    とりあえず、該当しそうな箇所に try{ /// }catch(Exception ex){ ex.ToString(); } を入れてみたが”非同期処理内、例外処理なし”のエラーしか出ない。

    困ってグーグル先生に聞いたところ
    「トレースログを出力する」
    とよいらしいという情報を得た。
    が、ログを出力するコードを追加したもののログを出力する前にエラーが出ているようで追加の情報は得られなかった。
    (付け焼刃でコードを追加したので追加箇所が正確ではない可能性がある。)

    これは困ったとだめもとで
    ”非同期処理内、例外処理なし”のエラーダイアログの「例外の詳細をクリップボードに追加」を実行した。


    System.Reflection.TargetInvocationException はハンドルされませんでした。
    HResult=-2146232828
    Message=呼び出しのターゲットが例外をスローしました。
    Source=mscorlib
    StackTrace:
    場所 System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
    場所 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
    場所 System.Delegate.DynamicInvokeImpl(Object[] args)
    場所 System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
    場所 System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
    場所 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    場所 System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
    場所 System.Windows.Forms.Control.InvokeMarshaledCallbacks()
    場所 System.Windows.Forms.Control.WndProc(Message& m)
    場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
    場所 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
    場所 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
    場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
    場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
    場所 System.Windows.Forms.Application.Run(Form mainForm)
    場所 Rainflow.Program.Main() 場所 C:\Users\xxxxxxx\Documents\Visual Studio 2015\Projects\Rainflow\Rainflow\Program.cs:行 19
    場所 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
    場所 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    場所 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    場所 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    場所 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    場所 System.Threading.ThreadHelper.ThreadStart()
    InnerException:
    HResult=-2146233086
    Message=インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
    パラメーター名:index
    ParamName=index
    Source=mscorlib
    StackTrace:
    場所 System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
    場所 System.Collections.Generic.List`1.get_Item(Int32 index)
    場所 Rainflow.DGV.d__3.MoveNext() 場所 C:\Users\xxxxxxx\Documents\Visual Studio 2015\Projects\Rainflow\Rainflow\Control.cs:行 316
    --- 直前に例外がスローされた場所からのスタック トレースの終わり ---
    場所 System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.b__6_0(Object state)
    InnerException:


    Message=インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
    この情報は大きい!そしてその下の
    場所 Rainflow.DGV.d__3.MoveNext() 場所 C:\Users\xxxxxxx\Documents\Visual Studio 2015\Projects\Rainflow\Rainflow\Control.cs:行 316
    ここが問題だそうだ。

    ということで、修正しました。
    例外処理はちゃんとしようね。
    メッセージ表示するだけでも効果あるある。
    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。