ゆくゆくは有へと

おかゆ/彼ノ∅有生 の雑記

Splatoon2のギアパワー計算式をもう少しキレイにする

こんにちは、スプラトゥーン2最高に楽しいですね。

ご存知の通り、ギアパワーの計算式ってのがありますが:

[1] ギアパワー検証 - Splatoon2 - スプラトゥーン2 攻略&検証 Wiki*

[2] ギアパワー効果測定【スプラトゥーン2調査 / Splatoon2】 – なんどろいどの開発記録

微妙に値が追いづらいので、もう少しエルゴノミックな形にしようとしました。

概要

xをギアパワー値、[MAIN]*10 + [SUB]*3とすると、

p = (0.99*x - (0.09*x)^2)

というのがギアパワーにほぼ普遍的に出てくる項で、これになんかしらの係数をかけたものが減少率・増加率に相当します。

ただ、このpなんですが、x = 57のとき p = 30.1131 くらいになってあまり覚えやすい値にならないので、基本値として、これを30で割った

X = (0.99*x - (0.09*x)^2) / 30

を定義することにします。そうすると、Xはギアパワー全振りでほぼ 1 になるので分かりやすいです。

で、さっきも言った通り、このXになんかしらの係数をかけたものが減少率・増加率に相当します。その係数を補正係数と呼んで、Rで表すと、

A = RX

となります。A は実際の減少率・増加率に相当します。

結局、基本となる値になんかしらの係数をかけるという点では変わらないんですが、このRの優秀なところは、この値自体が増加率・減少率の「最大」を意味するというところです。

例:インク効率(メイン)

例がないとよくわからないので、[1]のインク効率(メイン)のグループ1の場合を計算してみます。

[1]の計算式だと、基本となる値にかける係数は 1/60 であり、最大軽減率である 50% とはほぼ関連のない値になっています。

一方で、ここで提案した方法だと、R = 30 / 60 = 0.5 となって、これはまさに最大軽減率 50% のことを意味します。

最終的に、実際のインク効率 Z は、デフォルト値を D とすると、

Z = D * (1 - RX)

で求められ、各パラメータ R, X, D が意味を解しやすいものとなっていてエルゴノミックです!

有意味なパラメータ

結局、この方法だと

  • R: 変化率の最大値
  • X: 最大変化率に対する割合
  • D: デフォルト値

について把握しておけばOKということになります。

従来の、実際のステ変化とあまり関連づけて覚えられない係数より断然覚えやすいかと思います。

X の変化具合

とはいえ、より直観的に把握するためには、X とギアパワー値の対応関係についても覚えておく必要がありますが、この関係は二次関数的であって、そんな簡単に覚えておけるものでもありません。計算すればいいんですが、面倒ですしね!

なんで、主要な各点の値を把握してればいいんじゃないかと思います。

x = 0, 10, 20, 30, 39, 48, 57 に対して、それぞれ

X = 0, 0.30, 0.55, 0.75, 0.88, 0.96, 1.00

となります。%表示にするなら、30%, 55%, 75%, 88%, 96%, 100% ですね。

さっきのインク効率(メイン)の例を再び持ってくると、グループ1の武器で、メイン1つ付いていれば、R = 0.5X = 0.3 すなわち、最大軽減率 50% の 3割、15% くらいのインク効率アップが見込めるということになります。

ヒト速の通常歩きもR = 0.5 なので、メイン2個つければ50%の55%、だいたい27.5%の速度アップが見込めます。

X の線形補間

上の主要点の値を把握しておけば、これの線形補間で間の値も概算できます。

たとえば、x = 16におけるX(%) は、

X(%) = 30 + 6 * (55 - 30)/(20 - 10) = 30 + 6 * 25/10 = 45

となります。厳密な式に従えば、X = 45.9 なので、ほぼ値を捉えられています。

まとめ

コンピュータに計算してもらったほうがはやい

Pythonのスライシングの速度に気をつけて

今日のAtcoderのコンテスト(ABC)で死んだので自戒を込めて。

Pythonのスライシングが遅い話

Pythonのスライシングってリストコピーされるんでしたね……。通りで遅いわけ……。

で、スライシング使わずにdelしたのが次の2つ

Submission #1564678 - AtCoder Beginner Contest 072

Submission #1564698 - AtCoder Beginner Contest 072

前者はリストの前から削除していくやり方。

ところでPythonでは挿入や削除は後ろからしたほうが速いので、後ろから削除していくやり方が後者。

実行速度が5倍に…(´・_・)(´・_・)

いやあ、インプレースな操作(とリストの得意なやり方)って大事ですね…(´・_・`)

Disjoint set を勉強した AOJ #2512222 - Python編

Disjoint Set: Union Find Tree | Aizu Online Judge

AOJの解説とは異なり、root が自身へのポインタではなく、その木の集合を持つようにしてある。

当たり前ながら、破壊的更新ができるなら冗長な構造ですけど、ちょっと先のことも踏まえてこうした。

Pythonの集合はたしかハッシュセットなので、そこまで極端に速度落ちないことを期待する。

あと、競プロにありがちなデータ入力が毎回打つのダルすぎて、Stdinクラスに関数をまとめた。

パターンマッチ使いて~~~~~~~~~~~~~~~~~~~~~~~

Aizu #2512222

勉強がてら二分木をつくった回

純粋関数型データ構造

純粋関数型データ構造

今これ↑を読んでて、二分木の実装を練習がてらRustでしてみようと思ったのがきっかけ。

BTreeを実装しようとした

下の木をムーブしないようにmatchref 付けまわるのがたいへんでした(小並感)

やってて気づいたけど、この本にあるように、下の木を共有するの、Rustじゃデフォでできんや~ん

純粋だからこそ共有できるんやね(あたりまえのことをじっかんする)。

〈じゅんすいかんすう型でーたこうぞう〉の二分木をつくるなら、Rc使えばよさそうですね:

純粋な二分木

たぶん

追記 8/24 3:00

RustのBTreeMapはどうなってるんだろうと思ってソース見てみた:

doc.rust-lang.org

んんっ、なんだこのnodeモジュールとやらはっ ソースどこにあるんだろわからん

指定文字消すのどうすればいいんや

abc002.contest.atcoder.jp

“The Rust Programming Language” の第二版を最終章除いて読み終わったので、Atcoderでぽちぽちコード書く練習してるんだけど、 API全然知らないのでもうわっかんな~い(へらへら)

ありがたい………

qiita.com

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = buffer.trim().to_string();
    for ch in "aeiou".chars() {
        word = word.split(ch).collect::<Vec<_>>().concat();
    }
    println!("{}", word);
}

効率的な文字の消し方が分からんかったので、各母音字でsplitして集めてを繰り返すという微妙なやりかたをした。

調べてて気づいたが、collect::<Vec<_>>().concat() でなく、collect::<String>()にしたほうが賢いね。
collectFromIteratorトレイトのメソッドで、charイテレータStringにコレクトできるので。

というようなことを考えてると、for文消したくなるね。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word = buffer.trim().to_string();
    let word = "aeiou".chars().fold(word, |w, c| w.split(c).collect::<String>());
    println!("{}", word);
}

畳み込めばいいよね!ってことで畳み込んだ。

もう少し素朴なやりかた。containsStringpushをおぼえた。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = String::new();
    for c in buffer.trim().chars() {
        if !['a', 'e', 'i', 'o', 'u'].contains(&c) {
            word.push(c)
        }
    }

    println!("{}", word);
}

&strcharの配列なりスライスではないので、if !['a', 'e', 'i', 'o', 'u'].contains(&c)と書かないといけないのがPythonマンのおかゆには厳しさがある。

if !"aeiou".chars().collect<Vec<_>>.contains(&c)とすればいけるけど。もっと簡単な書き方あるのかな~。

と色々書いてて思いついたけど、filter使えばいいのでは……?

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .chars()
                             .filter(|c| !['a', 'e', 'i', 'o', 'u'].contains(&c))
                             .collect();
    println!("{}", word);
}

やっぱイテレータ触るならチェーンやで……!といわんばかりのチェーン 単語を文字のイテレータにして、子音だけパスしてコレクト。リストの内包表記こそ使えないものの、それにいちばん近いのは今までの中ならこれかな?

Pythonでなら、多分こう書くもんな:

word = "".join([c for c in word if c not in "aeiou"])
print(word)

f:id:waraby0ginger:20170807012446j:plain

追記(2017/8/7/20:05):replace あるやんけ

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .replace(&['a', 'e', 'i', 'o', 'u'][..], "");
    println!("{}", word);
}

あれからstrのこと調べてると、スライスとstrcontains, starts_with, ends_with, find, split系の引数が違うらしいことを知った。

strでは、要素1つの代わりにパターン(Patternトレイトを実装している型)を取るらしい:

  • &String
  • &[char]
  • char
  • FnMut(char) -> bool
  • &&str
  • &str

文字1文字はもちろんのこと、部分文字列やら、char.is_numericといった関数も与えれるので、結構柔軟にパターンが作れるらしい。

特に、&[char]論理和(って言い方であってんのか)なので便利…。

ちなみにおかゆは .replace(&['a', 'e', 'i', 'o', 'u'], "") ってして「&[char; 5]はダメっぷ~~~~ww」ってコンパイラに言われてキレてたんですけど、
ジェネリクスのトレイトバウンドの箇所では諸々の型強制(今回だとunsize coercion)が効かないの忘れてた(てへぺろ

Coercions -

こういう場面で型強制効かないのって安全のため?なんだろうけど、トレイトバウンドに使うときに融通の効くトレイトを作るのって結構大変そうだね。

人工言語学Wikiの「関与原理」へのコメント

ja.conlinguistics.wikia.com

コメントがあって、コメントしようとしたらなぜかこの記事にだけログインできない謎に遭遇してコメントできなかったので、ここに書いておきます。


はじめまして、おかゆです。

Yuhrさんの「格標示に比べれば関与は暗黙的ですが、そもそも、発話されている(言語形式としてそこに存在している)というだけでとんでもない明示と言えるでしょう。」という説明のほうが、本記事よりも関与原理についてよりよく的確に説明しているように感じます。関与原理のエッセンスというのは、言語形式としてそこに存在することの甚大な有標性だと思います。

本記事では、「関与原理」は意味役割の理論の中で説明しようとされていますが、実のところ、関与原理のいう「関与」は種々の意味役割よりも根本・原始にあると思います。

なぜ意味役割と同じ領域の中で「関与原理」を説明しようとしたのか、その動機はちょっと失念してしまいました。ただ、格体系のデザインの話になると、(特に工学言語の分野だとありがちですが)意味役割を格の形式として網羅的に分離しきりたいだとか、動詞のもつ意味役割の体系を完全に明示したいというような、意味役割体系における網羅性・完全性の強迫に駆られることがしばしばありますが、そもそも意味役割云々以前の問題として「言及したい対象について、そこで言い表している」という事実にはたいへん大きな価値があって、多くの語りたいことにとっては、その「言い表しによる有標化」だけで(意味役割を表示することなく)十分なんじゃないか、というようなことを考えて私は「関与原理」などと言い始めたような気がします(そうであれば、意味役割と紐付けて関与原理を説明しようとした動機にもある程度察しがつきます)。「関与原理」自体は「話者は、言いたいことを言い表している(あるいは言い表そうとできる)」というような至極当たり前のようなことに名前をつけただけに過ぎないと考えることもできます(なので私は「原理」と呼んでいるわけですが)。

拙い返事ですみませんが、これで。


Rustのmoduleの話

`mod` and the Filesystem - The Rust Programming Language

mod client {            //
    fn connect(){}      // -> client.rs
}                       //

mod network {           //
    fn connect(){}      //  ------ -> network/mod.rs
                        // |
    mod server {        // |
        fn connect(){}  // | -> network/server.rs
    }                   //  ------
}                       //