マサバ海峡タコ景色

Nintendo Direct 2023.2.9 | 任天堂

今回はスプラDLCくらいか。取り合えず夢を見る島をやろう。ゼルダ新作は買うけど、前作が神ゲーなのは認めるが何でか大してハマらんかったから実はそんなに期待はしてない。

気象庁|気象情報

大雪。籠れ。

Webpack から Vite に段階的に移行しました | PR TIMES 開発者ブログ

今年はこういう事例がポツポツ観測されそうだよな。State of JSでもViteがアゲアゲだったし。または時間が経てばTurbopackも選択肢になってくだろう。 Webpack よや すら かに。


GitHub - frozenpandaman/s3s: Successor to splatnet2statink. Takes battle data from the SplatNet 3 app and uploads it to stat.ink! が戦績データをローカルにJSONで吐き出せるのを見つけたので、適当にMackerelのサービスメトリックにブン投げてみる。特に意味はなく数値を抽出するだけ。

open System
open System.IO
open System.Net.Http
open System.Text.Json

type PlayerResult =
    { kill: int
      death: int
      assist: int
      special: int
      noroshiTry: int option }

type Player =
    { isMyself: bool
      paint: int
      result: PlayerResult }

module Player =
    let isMyself player = player.isMyself

type MyTeamResult =
    { paintRatio: float option
      score: int option
      noroshi: int option }

type MyTeam =
    { players: Player list
      result: MyTeamResult }

type VsRule = { rule: string }

type BankaraMatch = { earnedUdemaePoint: int option }

type VsHistoryDetail =
    { myTeam: MyTeam
      vsRule: VsRule
      bankaraMatch: BankaraMatch
      playedTime: DateTimeOffset }

type Data = { vsHistoryDetail: VsHistoryDetail }

type GameResult = { data: Data }

module GameResult =
    let load path =
        async {
            use reader = new FileStream(path, FileStreamOptions(Mode = FileMode.Open))

            return!
                JsonSerializer
                    .DeserializeAsync<GameResult list>(reader)
                    .AsTask()
                |> Async.AwaitTask
        }

    let after than result =
        result.data.vsHistoryDetail.playedTime > than

type Metric =
    { name: string
      time: int64
      value: float }

module Metric =
    let fromResult result =
        let detail = result.data.vsHistoryDetail
        let player = detail.myTeam.players |> List.find Player.isMyself
        let result = detail.myTeam.result
        let bankara = detail.bankaraMatch

        let time =
            detail
                .playedTime
                .ToLocalTime()
                .ToUnixTimeSeconds()

        let (=>) name value =
            Some
                { name = $"{detail.vsRule.rule}.{name}"
                  value = value
                  time = time }

        let (=>>) = (=>) >> Option.bind
        let (=>>>) name = Option.map float >> (=>>) name
        let (%) = (*) 100.

        [ "paint" => player.paint
          "kill" => player.result.kill
          "death" => player.result.death
          "assist" => player.result.assist
          "special" => player.result.special
          "paintRatio" =>> Option.map (%) result.paintRatio
          "score" =>>> result.score
          "noroshi" =>>> result.noroshi
          "earnedUdemaePoint" =>>> bankara.earnedUdemaePoint
          "noroshiTry" =>>> player.result.noroshiTry ]
        |> List.choose id

module Mackerel =
    let send (apiKey: string) (serviceName: string) (metrics: Metric list) =
        async {
            use writer = new MemoryStream()

            do!
                JsonSerializer.SerializeAsync(writer, metrics)
                |> Async.AwaitTask

            writer.Seek(0, SeekOrigin.Begin) |> ignore

            use content = new StreamContent(writer)
            content.Headers.Add("X-Api-Key", apiKey)
            content.Headers.Add("Content-Type", "application/json")

            use http = new HttpClient()

            let! res =
                http.PostAsync($"https://api.mackerelio.com/api/v0/services/{serviceName}/tsdb", content)
                |> Async.AwaitTask

            return! res.Content.ReadAsStringAsync() |> Async.AwaitTask
        }

let RESULTS_JSON_PATH = "path/to/results.json"
let API_KEY = "xxxxxxxxxxxxxxxxxxxxxxx"
let SERVICE_NAME = "Splatoon3"

async {
    let! results = GameResult.load RESULTS_JSON_PATH

    return!
        results
        |> List.filter (GameResult.after (DateTimeOffset.Now.AddDays -1))
        |> List.collect Metric.fromResult
        |> Mackerel.send API_KEY SERVICE_NAME
}
|> Async.RunSynchronously
|> printfn "%s"

出てきた昨日の様子。

なるほどー。

今シーズン前半ずっとサボってたからロブさんノルマが終わりそうにないんだけど、塗りポイントの積み上げでバーンアップチャートにすれば予測立てれそうだな。

ついでにs3sのコードざっくり読んでみて、これを参考に直でゴニョゴニョすればもっといろいろ効率よくできそうだなとは思ったけど、いろいろアレな感じなのでアレです。しかしGraphQLを自力でここまで解析したんだとしたらすげーな。

S+ダメです