日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

Splatoon2から始めてウデマエXまで行くときにやったりしたことの備忘録

この記事はSplatoon Advent Calendarの1日目として書かれています。
勢いで作ったら結構埋まっててとても嬉しいですw

adventar.org

なにを書こうか悩んだんですが、
Splatoon2が発売されてからウデマエX行くまでを振り返って、
自分がどうやってウデマエXまで行けたかを書いてみようかなと思います。
ウデマエXを目指す方のなにか参考になれば嬉しい限りです。

今のウデマエと使用武器

普段の使用武器はマニューバ系やシューター系の短距離から中距離のブキを持っています。
今現在のXパワーは2100 ~ 2300強くらいをさまよう、一部ではX底辺と言われたりするくらいのウデマエです。

初めS+0までのとき

初めS, S+0まで行ったときはずっとボールドマーカーを使っていました。
特にルールごとになにか考えることもなくプレイしていた気がしますw
唯一やってたことは率先してオブジェクトに絡むことをしていました。
エリアだったらエリアを塗る。
ヤグラだったらヤグラに乗る。
ホコならホコを持つ。
自分以外がやらなそうだったら自分がやるようにしてたら上がれたような気がします。

A+ ~ S+2あたりをウロウロしてるとき

S+0までは発売から3ヶ月ほどですんなり一度上がれたんですが、
その後立ち回りがわからなくなってきてウデマエが上がったり下がったりするようになりました。
正直ボールドマーカーに限界を感じるようになったのでいろんな武器を使うようにしました。

エリアでは

  • ボールドマーカー
  • スクリュースロッシャー
  • N-ZAP85
  • N-ZAP89
  • ダイナモローラーテスラ
  • バケットスロッシャーデコ
  • スパッタリーヒュー

ヤグラでは

  • ジェットスイーパー
  • ホットブラスター
  • もみじシューター
  • スパッタリーヒュー

ホコでは

  • ボールドマーカー
  • バケットスロッシャーデコ
  • スパッタリー
  • スパッタリーヒュー

アサリでは

  • スプラローラー
  • ホットブラスター
  • デュアルスイーパー
  • スパッタリーヒュー

などを使っていました。
かなり迷走気味ですね。
でも、これをやってよかったなと思うことがありました。
使っていた武器との対面の仕方や、その武器がどこに立ちたくなるかのポジションがわかるようになったことです。
どこに潜伏してそうかとか、どういう行動をあの武器はやられたら嫌かがわかると、
それらの武器に対して優位に対面できると思うので、
いろんな武器を持ってガチマッチに潜ったのはつらかったけど本当によかったなと思います。

S+の数字を上げていったとき

いろんな武器を持っていたんですが、
アメフラシが強いなーと思ってたのと、キル性能が高かったのもあり
スパッタリーヒューに使用武器が固定され始めて、
ようやくS+にも数字がついて落ち着くようになってきました。
その頃ちょうどウデマエXが出るという話が出てきたので、
S+10くらいまでなら頑張りたいなと思ってどうやったらよくなるかを考え始めた時期でした。
そこでやったのが上手い人の動画を見て学ぶということでした。
今考えると、もうちょっと早くやっても良かったんじゃないかなとかよぎりますねw

エリア

まずはエリアですが、
スパッタリーヒューを使っていこうと思ってたのでYoutubeで探したら、
あしんさんという配信者さんがガチエリアでの立ち回りを解説している動画や、
よくやってる試し打ちを動画にされていたのでそれを見てとりあえず丸パクリして徐々にアレンジしていくことにしました。

www.youtube.com

www.youtube.com

エリアの立ち回りの動画を見たとき、
打開とか抑えの考えを一切自分は持ってなかったので、本当に参考になりました。
打開時にちゃんと味方と合わせるというのが大事で、
それさえ出来たらあとはサクサク数字が上がって4種の中で一番はじめにXになりました。
途中でX導入されたので元々強かった人々がいなくなったってのもありそうですがw
あとは試し打ちをちゃんとやったらエイムがかなり良くなって対面も勝てるようになったので、
ちゃんとやると効果出てよかったです。
バスケでもシュート練習しないとシュートはいらなくなるし、
ピアノでも練習しないと指動かないしなーとか思ってやっぱ練習大事だなと思いました。

ヤグラ

ヤグラはS+0に行った後に、様々な武器を使ってAまで落ちてしまい、
その際、もみじシューターを使って這い上がってきたんですが、
塗り拡げてキル武器にキルを取らせて、自分がヤグラに乗って、止めるときは雨をはけば勝てると思ってたので、
特段探さず殺傷能力の上がったスパッタリーヒュー+アメフラシでどうにかしていましたw
デュアルスイーパーカスタムが出た後は更に塗りやすくなったので持ち替えて、
塗りながらヤグラに乗ってアメフラシで止めるという方針でXまで行きました。

ホコ

ホコは結構好きだったんですが、
苦戦してたので探したらメシアはボールドさまという配信者さんの動画を見つけて参考にしてました。

www.youtube.com

この時まで何も考えずホコを進めてたんですが、
ゴールから限りなくホコを遠ざけるとか、どこまではホコを進ませても大丈夫とかそういう考え方を気付かされた動画でした。
どこまでには必ず止める。
無駄に突っ込まないが大事ですね。
ホコ持ちが得意だったこともあり、この考え方のおかげでわりとすんなり上がることが出来ました。
ホコではスパッタリーヒューよりスパッタリーをよく使っていました。

アサリ

アサリはエリアのおかげで周りが見えるようになって特段なにもなく上がってしまったので割愛しますw
武器はデュアルスイーパーカスタムがでて使いやすかったのでずっとデュアルスイーパーカスタムを使っていました。

まとめ

所感としては個人的には

  • ある程度ルールなれるまではひたすら同じ武器を使うとよかった
  • ガチマッチはオブジェクトに絡むようにするとよかった
  • ガチマッチ慣れてきたらいろんな武器をいろんなルールで使ってみるとよかった
  • 立ち回りよくわからなくなってきたら動画を見て真似してみるとよかった

という感じでした!
もしSplatoonやっててなにか悩んだ人の参考にでもなればとても嬉しいです!

Scala製ValidationライブラリのAccordを触るぞい

最近Scalaのコードを書いててフレームワークに付随しないタイプのValidationのライブラリなんか無いかなー
と探していたらAccordというものを見つけたので触ってみた備忘録です。

Accord: A sane validation library for Scala

準備

検証用リポジトリはこちらで、使ったライブラリのversionは0.7.2でした。

github.com

installはbuild.sbtのlibDependenciesに追加する感じですね
書いたbuild.sbtはこんな感じでした

val commonSettings = Seq(
  version := "0.1-SNAPSHOT",
  scalaVersion := "2.12.5",
)

lazy val root = (project in file("."))
  .settings(commonSettings)
  .settings(
    name := "scala validation sample",
    libraryDependencies ++= serverDependencies
  )

val serverDependencies = Seq(
  "com.wix" %% "accord-core" % "0.7.2"

)

Accord概要

Accordのvalidationは特定の型に対するValidatorを定義して、
com.wix.accord.validate関数がそのValidatorを利用してvalidationを行い、
最終的にはResult traitを継承した(?)SuccessかFailureを返すみたいな形みたいですね。
validate関数はimplicit parameterでValidatorを渡せるようになっているので、
スコープ内にValidatorを定義しておけば引数から渡さなくても渡せますね。
明示的に渡したい場合は第二引数(?)に渡してあげれば渡せますね。

Ref: http://wix.github.io/accord/api.html#execution

使ってみた

実際に書いてみたコードはこんな感じでした。
APIサーバとかで使うならJSON形式で゚来たRequest Bodyをなんらかのcase classのオブジェクトにマッピングして、
そのオブジェクトをvalidationするみたいな形にするかなーとか思いながら書いてました。

package com.ru.waka

import com.wix.accord.{NullSafeValidator, RuleViolation, Validator, validate}
import com.wix.accord.ViolationBuilder.singleViolationToFailure
import com.wix.accord.dsl._

object Accord {
  implicit val hogeValidator: Validator[Hoge] = validator[Hoge] { h =>
    h.a is notEmpty
    h.b is in(1, 2)
  }

  implicit val FugaValidator: Validator[Fuga] = validator { f =>
    f.as has size > 0
  }

  implicit val PiyoValidator: Validator[Piyo] = validator { p =>
    p.as is notEmpty
    p.bs is myNotEmpty as "その値"
  }

  /**
    * @see http://wix.github.io/accord/dsl.html#combinators
    */
  def main(args: Array[String]): Unit = {
    println(validate(Hoge(a = "", b = 10)))
    // Failure(Set(a must not be empty, b with value "10" got 10, expected one of: [1, 2]))

    println(validate(Fuga(Nil)))
    // Failure(Set(as has size 0, expected more than 0))
    println(validate(Fuga(Seq(1, 2, 3))))
    // Success

    println(validate(Piyo(Nil, Nil)))
    // Failure(Set(as must not be empty, その値 List() は空じゃだめなんじゃ〜))
    println(validate(Piyo(Seq("a"), Seq(1))))
    // Success
  }

  case class Hoge(a: String, b: Int)

  case class Fuga(as: Seq[Int])

  case class Piyo(as: Seq[String], bs: Seq[Int])

  def myNotEmpty[T <: Seq[_]]: Validator[ T ] =
    new NullSafeValidator[ T ](
      test    = x => x.nonEmpty,
      failure = x => RuleViolation(x, s"$x は空じゃだめなんじゃ〜")
    )
}

感想

  • 😁 Validationの成功失敗、失敗はどの項目がどのルールで失敗したかが返るので基本的なValidationの機能は満たしてる
  • 😁 既存のルールが割と多いので時前で定義せずともわりと使える
  • 😁 困ったら自分でも作れるのでまあ便利
  • 😁 レポジトリのStar数もそれなりにあるし、開発も続いてるし息短くはなさそう
  • 😥 エラーメッセージを日本語にしたいと思ったんだけど、既存のものを変える方法が見つけられてなくて困ってる
    • h.a as "変な値" is notEmpty みたいに定義しても 変な値 must not be empty となるのでメッセージ全体は変えられなかった
    • このあたりはもう少し深掘りしながらissueとかも見ていこうかなと思った

PHPのプロファイリングが出来るblackfireでPOSTリクエストもプロファイルする

以前blackfireを試したんですが、そのときはブラウザでページを開いて、
chrome extentionでプロファイリングしてました。
なのでGET以外のリクエストがプロファイルやりづらく、
もうちょっといいやり方無いかなと思って探してみました。

以前の話
arata.hatenadiary.com

やることはblackfire agentをどこかにインストールして、そこからcurlコマンドで計測するという感じです。
今回自分はMacでやったのでbrewで入れました。
インストール手順はこのあたりです。
configのid, tokenとサーバに設定するid, tokenは異なるので注意が必要です。
blackfire.io

実際にやってみるとこんな感じでした。

$blackfire config
--------------------------------------------------------------
 Welcome to the Blackfire CLI utility configuration assistant
--------------------------------------------------------------

Your Blackfire Client ID and Token are available at:
https://blackfire.io/my/settings/credentials#client

Enter your Client ID: XXX
Enter your Client Token: YYY
------------------------------------------------------------------------------
The following configuration has been updated successfully
/path/to/.blackfire.ini

Thank you for using Blackfire
------------------------------------------------------------------------------

サーバの実装として使ったレポジトリはこちら

github.com

blackfireはcurlコマンドをwrapしてくれるみたいです。
curlでのリクエストを取れればいいんですけど、そんなときに便利なのがchromeのdev toolですね。
こんな感じでリクエストをコピーしてきます。

実際blackfireでcurlをwrapして叩いてみました。
GraphのURLはごまかしてます。

# 対象のserver起動
$make compose id=xxx token=yyy                                                                         [master]@(blackfire-with-slim)
docker-compose build
Building web
Step 1/10 : FROM php:7.1.10
 ---> c342f917459a
Step 2/10 : RUN apt-get update
 ---> Using cache
 ---> 8f08514cd607
Step 3/10 : RUN apt-get install -y wget
 ---> Using cache
 ---> 558f46f226ce
Step 4/10 : RUN wget -O - https://packagecloud.io/gpg.key | apt-key add -
 ---> Using cache
 ---> dc02abcab12c
Step 5/10 : RUN echo "deb http://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list
 ---> Using cache
 ---> 947920d5728f
Step 6/10 : RUN apt-get update
 ---> Using cache
 ---> 98aa1854625d
Step 7/10 : RUN apt-get install -y blackfire-agent
 ---> Using cache
 ---> d0725ad5b875
Step 8/10 : COPY ./blackfire.ini /etc/blackfire/agent
 ---> Using cache
 ---> 9a8965d48d25
Step 9/10 : RUN /etc/init.d/blackfire-agent restart
 ---> Using cache
 ---> f6360b5dc8d4
Step 10/10 : RUN apt-get install blackfire-php
 ---> Using cache
 ---> 40f8638aca26
Successfully built 40f8638aca26
Successfully tagged blackfire-with-slim_web:latest
docker-compose up
Starting blackfire-with-slim_web_1 ... done
Attaching to blackfire-with-slim_web_1
web_1  | make: Entering directory '/opt/app'
web_1  | /etc/init.d/blackfire-agent start
web_1  | Starting Blackfire Agent: blackfire-agent.
web_1  | /usr/local/bin/php -S 0.0.0.0:8080 -t web

# 別ターミナルで実行してみます
$ blackfire curl 'http://localhost:8080/hey' -H 'Origin: http://localhost:8080' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' -H 'Content-Type: application/json' -H 'Accept: */*' -H 'Referer: http://localhost:8080/' -H 'Connection: keep-alive' --data-binary '{"name":"blackfire"}' --compressed
Profiling: [########################################] 10/10
Blackfire cURL completed
Graph URL https://blackfire.io/profiles/XXXXXXX/graph
No tests! Create some now https://blackfire.io/docs/cookbooks/tests
No recommendations

Wall Time     126ms
I/O Wait        n/a
CPU Time        n/a
Memory          1MB
Network         n/a     n/a     n/a
SQL             n/a     n/a

Graph URLで表示されているURLにアクセスするとこんなグラフが見れました。

POSTもラクラクプロファイルできて便利!

scalikejdbcを使ってMySQLにクエリを投げるだけのメモ

久しぶりにScalaを触ってMySQLにクエリを投げたいだけなんだけど、
それすらもぱっとは思い出せなかったので備忘録として書いとこうと思います。

scalikedjbc

github.com

検証用レポジトリはこちら。
make run で多分動きます。

github.com

build.sbt

とりあえずおもむろにbuild.sbtにscalikejdbcを追加します。
3系出てたんですね。
長いこと触って無くて知りませんでした。

scalaVersion := "2.12.5"

libraryDependencies ++= Seq(
    "org.scalikejdbc" %% "scalikejdbc" % "3.2.3",
    "mysql" % "mysql-connector-java" % "6.0.6"
)

書いたコードは結局このくらいでした。
localTxの実装を見たらなにかあったらThrowableが投げられるみたいだったのでcatchingで囲むことにしました。
Throwableが投げられたとしても特に何もしなかったらrollbackされなかったので、
投げられたら(Leftが返ってきたら)rollbackするような実装にしました。

package com.ru.waka

import java.time.LocalDateTime

import scalikejdbc.{ConnectionPool, DBSession, NamedDB, SQL}

import scala.util.control.Exception._

object Hello {
  private val connectionSymbol = 'testDB

  Class.forName("com.mysql.cj.jdbc.Driver")

  ConnectionPool.add(connectionSymbol, "jdbc:mysql://localhost/test?characterEncoding=UTF-8", "root", "")

  val repository = new HelloRepository(connectionSymbol)

  def main(args: Array[String]): Unit = {
    val time = LocalDateTime.now().toString
    NamedDB(connectionSymbol) localTx {implicit  session =>
      (
        for {
          _ <- createTable()
          _ <- repository.put(time)
          rs <- repository.fetch()
        } yield rs) match {
        case Right(rs) =>
          session.connection.commit()
          println(rs)
        case Left(th) =>
          session.connection.rollback()
          println(th)
      }
    }
  }

  def createTable()(implicit session: DBSession): Either[Throwable, Boolean] = catching(classOf[Throwable]) either {
    SQL(
      """
        |CREATE TABLE IF NOT EXISTS foo (hello varchar(100))
      """.stripMargin
    ).execute().apply()
  }
}

class HelloRepository(connectionName: Symbol) {
  def put(hello: String)(implicit session: DBSession): Either[Throwable, Int] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |INSERT INTO foo (hello) VALUES (?);
        """.stripMargin
      ).bind(hello).executeUpdate().apply()

  def fetch() (implicit session: DBSession): Either[Throwable, Seq[Map[String, Any]]] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |SELECT hello FROM foo;
        """.stripMargin
      ).map(_.toMap()).list().apply()
}

scalikejdbc.SQLの引数にクエリを渡して、
executeしてapplyすればクエリが走りました。
めでたしめでたし。
implicit parameterってどう使われるのかの理解が浅かったのでこのあたりも参考に読みました。

参考

いちいちsessionを渡さなくてもいい感じに渡してくれるので便利ですね。
(暗黙なのちょっと不安だけど)