プログラミング

    Pythonでシーザー暗号実装

    PAYDAY2 Blacklist Assist

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


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

    この間時間制限ありのPython問題集でシーザー暗号のプログラムを組むことがあったのですが、時間制限があるとだめだね。

    緊張して全然頭まわらない。

    プログラムの仕様としては
    • 文字列(変数名Message str型)
    • ずらす個数(変数名Key int型)
    • 暗号化した文字列(Result str型)
    • 暗号化する文字はa-zA-Zのみで,や:などの文字はそのまま表示する

    とりあえず、「文字をずらす!」ということをするので、ordで文字コードを取得して、a-zA-Zの間にあればKey分ずらすというものを書いたのだが、とても分かりづらいものになってしまった。

    後から考えてみると、
    小文字アルファベット、大文字アルファベットの文字列を用意しておき、その中から検索して、見つかればずらすとしたほうがスマートだったなと思ったので書いてみた。

    問題集では暗号化のみを扱っていたが、ついでなので複合もできるように拡張しておいた。

    import re
    
    def cryption_caesar(Message, Key, IsEncrypt):
        assert isinstance(Message, str), "Error"
        assert isinstance(Key, int), "Error"
        assert Key > -1, "Error"
        assert isinstance(IsEncrypt, bool), "Error"
        
        alf_s = "abcdefghijklmnopqrstuvwxyz"
        alf_l = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        
        result = ""
        
        if Key > 26:
            Key = Key % 26
        
        for e in Message:
            if re.search(r"[a-z]", e):
                if IsEncrypt:
                    if alf_s.find(e) + Key > 25:
                        result += alf_s[alf_s.find(e) + Key - 26]
                    else:
                        result += alf_s[alf_s.find(e) + Key]
                else:
                    if alf_s.find(e) - Key < 0:
                        result += alf_s[alf_s.find(e) - Key + 26]
                    else:
                        result += alf_s[alf_s.find(e) - Key]
            elif re.search(r"[A-Z]", e):
                if IsEncrypt:
                    if alf_l.find(e) + Key > 25:
                        result += alf_l[alf_l.find(e) + Key - 26]
                    else:
                        result += alf_l[alf_l.find(e) + Key]
                else:
                    if alf_l.find(e) - Key < 0:
                        result += alf_l[alf_l.find(e) - Key + 26]
                    else:
                        result += alf_l[alf_l.find(e) - Key]
            else:
                result += e
        
        return result
    

    cryption_caesarの3つ目の変数がTrueなら暗号化、Falseなら復号する。

    入力文字列 rin_jugatlaを暗号化すると
    sjo_kvhbumbとなる、これを復号すると
    rin_jugatlaに戻ると。

    あぁ、なぜ最初にこの方法を思いつかなかったんだろう・・・。
    assertのエラー文が雑とか、条件分岐も雑とかいろいろあるけど、まぁ動けばいいかな。
    スポンサーサイト

    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
    を返す。
    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。