高専5年の文化祭がおわったので振り返る

お久しぶりです.nanaminです.高専5年の文化祭(工嶺祭)が終わって一段落したのでいろいろかきます.

TL;DR

今回から試験的導入TL;DRくん.

ゲームサーバーをたてるとたのしい.でもゲーム(クライアント)側との連携でアホみたいに時間かけてしまったのが反省. 展示はうまくいったのでまぁまぁ満足.

展示したもの

去年(高専4年)の文化祭で展示した音ゲー「miditone」に

  • ゲームサーバーを立ててユーザーのスコアを保存できるようにした
  • WiiBalanceBoardでも遊べるようにした

のざっくり2点の機能を追加して新しく 「miditone#」として展示しました.

ユーザーの識別にはQRコードを使い,ユーザー登録のタイミングでQRコード生成&印刷,それをゲーム開始時にカメラで読み取るという方法をとりました.

開発したもの

githubリポジトリ github.com

  • ゲーム本体
    • OpenSiv3D v0.4
  • サーバのAPIクライアント
    • Boost/Asio とか
  • WiiBalanceBoardとの通信
  • ランキング表示アプリ(未完成)
    • OpenSiv3D v0.4
  • ユーザー登録用のAndroidアプリ
  • ゲームサーバ

去年と同様,友人のOpenSiv3Dマンのshirryに描画部分をやってもらい,ゲームサーバの開発と APIクライアント,WiiBalanceBoardとの通信はぼくが担当しました. バイトでRailsAPIをやっているので,その知識が役に立ってよかったです.

ユーザー登録のAndroidアプリはもう1人の友人にやってもらいました.たすかる.

先に反省

ゲーム開発むずいっす

APIクライアントに時間をかけすぎてしまった

冒頭でも書きましたが今回ゲームとサーバの連携,つまりAPIクライアントの部分でアホほど時間をかけてしまいました... サーバはJSON APIとして実装したので,決まったURIに決まったメソッドでHTTPリクエストを投げるとJSONを返すようになっています. ここでそのレスポンスをゲームでいい感じに使えるようにパースする必要があるのですが,きれいなコードを書こうと凝りすぎて無限に時間を消費してしまいました. template多用おじさんで,すいません.

クラスメートを譜面制作にもっとまきこみたかった

ぼくの声かけ&準備不足なのですが,WiiBalanceBoard版の譜面をもう少し増やしたかったです.開発に手一杯でそれどころじゃなかった. 展示当日WiiBalanceBoard版が空気になってたのでちょっとさみしかったです.

ユーザ登録に時間がかかりすぎる

これは完全に想定外で,

  1. AndroidアプリからプリンターにQRコード印刷キューを投げる
  2. プリンターがQRコードを印刷する

この部分で30秒くらいかかるのがとてもつらかった.開発中は「まぁ待ち時間中にやってもらうし大丈夫やろ...」と軽く受け止めていたのですが実際運用してみるとかなりつらい. QRコードの生成と印刷を予めしておけばよかったのかなって今思ったり

ランキング表示アプリ稼働したかった

開発が間に合わなくて稼働できなかったランキング表示アプリくん... 予定ではトータルスコアランキングと人気曲ランキングを表示するはずでした.まぁしょうがない

デスマ開発やめたい

台風19号で工嶺祭が2ヶ月くらいのびてもデスマしちゃう.なんか時間があると追加機能つくりたくなっちゃうよね.しょうがないね. shirryにたくさんissueをふってしまいました.対応してくれてほんとうにありがとうございます.

感想

いろいろ反省点が出てきましたが,とりあえず展示はなんとかなってよかったです. ゲームサーバの開発というなんかかっこいいことができてよかったです.あとDockerもすこし分かってきてよかったです.

ゲームに自分のハイスコアが出てきたり他のプレイヤーのスコアが出てきたりするとテンション上がるよね. ゲームサーバたてるとなんかまじでゲームっぽいことができるのでおすすめです.

RaspberryPiにゲームサーバ立てつつWiFiのAPにしたので,ネットワークの知識がだいぶ役に立ちました. 高専4年のネットワーク基礎はまじで人生の役に立つ.あとマスタリングTCP/IP.shirryがネットワーク強いのでとても助けられた.

今振り返るとと夏休み(9月)くらいからずっとやってきたんだなぁ.ながい.10月に産業フェアにも展示したりして なんかずっとやってる.

謝辞

台風19号が工嶺祭1週間くらい前に直撃して一時は工嶺祭中止になってゲーム開発者として虚無になるところだったけど,こうやって一般公開することができてよかったです. 関係者のみなさん本当にありがとうございます.

また,このゲーム制作にかかわったshirry,クラスメート,先生方にもお礼を言いたいです.

編集あとがき

ふつうに感想を書こうとしたけど,途中で実装面も触れたほうがいいような気がして文章がどっちも寄りになった気がする. 文かくのむずかしいね

初めて自作PCを組み立てた話

お久しぶりです.nanaminです.先日自作PCを初めて組み立てたので,記事にしてみました.適当に書いたので語尾が安定してないです.

動機

去年の12月くらいにWindowsノートPCをぶっ壊してMacBookだけになってしまい,流石にしんどかったので.あとバイトの給料がアップしてお金がたまってた.

方針

OS抜きで予算10万円くらい.ゲームはほぼしないのでGPUよりもRAMをもりもりに. 某OSを使ってみたいのでIntel CPUとRadeon縛り.置き場所には困ってないし組み立てが容易なATXサイズ

構成

f:id:Nanami0634:20190903220218j:plain
買ったパーツたち

パーツ選び雑感

パーツ選びに関して,このやかもちさんのサイトが大変参考になりました.ありがとうございます. chimolog.co

GPU → CPU → RAM → ROM → マザボ → 電源の順で選びました.たぶんこの順番で決めるのが楽な気がします.予算が10万円なのでCPUとGPUコスパ重視で決めました.マザボを決めるのが一番大変でした.チップセットとCPUの対応がよく分かってなかったのでZ390のちょっといいやつを買ってしまいました.でも将来性あると思えば問題ないです.

RAMは最初Crucialの16GB2枚のやつを買おうとしてたんですが,全然入荷の目処がたたずCorsairのやつに変更しました.今安いので仕方ないですね.

電源はGOLDを選びました.たぶん起きている間ずっとPCを立ち上げてそうだったので,ここは少しいいやつにしました.サイトによってPCの消費電力の計算結果がだいぶ違って迷いましたが550Wになりました.

ケースはほぼデザインだけで選びました.LEDピカピカ〜よりはおとなしくしててほしかったので黒基調でシンプルなものを選びました.かっこいいです.

SSDとメモリがとても安くて助かりました.このあと同じ型で500GBのSSDを2つ買って全部SSDだけで運用することになりました.贅沢.

OS抜きで10万ちょいくらいで収まりましたが,SSDを2つ追加で買って結局12万ちょいくらい使ってしまいました.

組み立て

CPUのピン折らないか心配だったけどなんとかなった.それよりもメモリを刺すのが硬くて壊さないか心配だった.マザボをケースに入れるときもいい感じにはまらなくて大変だった.ケースのバックパネル用の穴に入れるのがむずい.

配線をきれいにやるのが難しかった.SSDを3つつけてるのでSATAケーブルが暴れてケース締めるのが大変だった.

結局組み立てと配線でいろいろしてたら6時間くらいかかった.

f:id:Nanami0634:20190903221603j:plainf:id:Nanami0634:20190903221556j:plain
うごいた!

セットアップ

某OSを安定させるために1週間くらいかかった.これでWindowsと某OSとUbuntuが入ったので優勝した.OSでSSDを物理的に分けてるのでWindowsくんがパーティションをこわしても大丈夫.あと,同じ型のSSDを買ったせいでBIOSとかの表示が同じで見分けがつかなくてめんどかった.

f:id:Nanami0634:20190903224924j:plain
ブートローダの最初の画面.アイコンがないのはUbuntu

ベンチマーク情報

ネットにあるものと同じくらいのスコアで安心.

f:id:Nanami0634:20190903222241p:plainf:id:Nanami0634:20190903222244j:plainf:id:Nanami0634:20190903222249j:plain
ベンチマーク情報

実際使ってみて

今までHDDに入ったWindowsしか使ってこなかったので圧倒的サクサクに感動してる.サクサク〜最高! あとこれ↓につきる.

今までメモリ8GB MacBookだったので快適すぎてやばい.スワップ領域とか知らない世界.というかメモリ使用量50%まだいってない.VSプロジェクト2つとStudioOneとChrome1.5GBメモリ使ってるのに.

あと,GROOVE COASTER for Steamがまたできるようになったの嬉しい.みんな買え store.steampowered.com

まとめ

自作PCって楽しい.パーツ選び難しいけど楽しいし自分で選んだものなのでPCへの愛着がやばい.経済回してけ ⁽⁽卍卍₎₎

編集雑記

今回昼夜逆転して脳が溶けてる状態で書いたので文がぐちゃぐちゃです.でも脳から出た言葉そのまま出してるので割と早く書けました.

就/活イベントSクリア

お久しぶりです.nanaminです. 先日,内定承諾書を出してやっとぼくの就活が終わりました. 人生の一大イベントである?就活なので,忘備録的なものとしてブログとして残します.

就職先

某ゲーム会社に内定をいただきました.

時系列にいろいろと書いてく

進学 or 就職

ぼくは高専生なので,進路として選択肢にあるのは,

  • 大学への編入
  • 就職
  • 起業(レア)

の3つでした. 起業は僕の性格上ないとして,編入か就職でとても悩みました. 4年生夏のインターンの時期では就職希望でしたが,10月のマイナビさんの就職説明会では 就職か編入か半々くらい,12月頃は編入希望と,希望が編入へ変わっていきました

1月に高専生用の合同説明会というのに参加して,編入ではなく就職しようということで自分の中で結論が出ました. その説明会では,高専生を多めにとってくれる企業がたくさんいたわけですが,その中にゲーム会社もちらほらいたのが 就職希望へと変えるきっかけでした.もともとプログラムをたくさん書ける仕事がいいなぁと漠然と当時考えていましたが, その説明会にいたゲームプログラマーの話を聞いて就職の方が楽しそうだなぁと思った次第です. やっぱり,実際に会って話してみたりすると考えがまとまったりするかもしれないです.

企業選び

10月の就職説明会でよくある就活アプリを入れさせられるわけですが,1月の終わり頃になると企業選びのために活用することになります. 高専で書いてきたプログラムがCGなどのグラフィック系が多かったのでゲーム関係を中心に探し始めたんですが,とにかく数が多くて選ぶのが大変でした. 僕は長野県に住んでいるため,東京に本社があるゲーム会社をたくさん選ぶのは交通費的にきついのでとりあえず3社まで絞りました.

  • 僕の好きなゲームを作っている
  • 事業領域的に僕のやりたいことができそう

みたいな理由で選びました.

エントリーシートかきかき

3月になるとインターンが始まったり,エントリーシートの提出受付が始まったり就活がめんどくさくなってきます. エントリーシート!が!とてもめんどくさい! 文章書くのがとても苦手なので1社書き上げるのに1週間弱くらいかかりました. ゲーム会社なので1項目300〜400字くらいでまだ良かったです. 自己PRはだいたい使い回せますが,志望理由は企業によって変わるので書くのが難しかったですね. あと,エントリーシートに書く用のプログラム作品を用意するのも大変でした.ドキュメント整理とかしなきゃいけないので. こういうときのために準備しておくのがいいと思いました(小並)

筆記試験とかSPIとか

SPIは正直対策しなくても通ったのでよかったです. ある程度,その業界で必要な知識(僕の場合ゲーム会社なのでアフィン変換とか運動方程式とかそこらへん)やある程度の英語力があればいけます.

面接 𝑻𝑰𝑴𝑬

エントリシートがいい感じになると面接が4月くらいに始まります. 最初の面接はとても緊張しましたが,意外となんとかなります. ゲーム会社というのもあってか,私服可でとてもフランクに話しかけてくれたので助かりました. また,相手は現役のプログラマーということもあって話しててとても楽しかったです.自分の興味ある分野の技術を熟知しているわけなので, 同じ話題で盛り上がれることがとても嬉しかったです.高専時代で書いてきたプログラムや作ったゲームなどは会話がすごく盛り上がりました. あとは入退出のマナーだけおさえておけば完璧です.

最終面接だけ私服不可の企業もあり,そこはとても緊張しました.もうやりたくないです.

格通

ぼくは3社応募したわけですが,そのうち1社は最初の面接で落ち,そのうち1社は最終面接で落ち, なんとか1社から内定をもらうことができました.ほんとよかったです. 合格通知は最終面接の次の日に来てたっぽいんですが,タイミングが合わずその2日後に電話を取ることができました. ちょうど弐寺のクレを入れてICカードをかざす直前にタイミングよくかかってきたので焦りました. 合格の旨を聞かされたときは流石に脳がバグりました.3秒間くらい合格という単語の意味について脳内で何重もチェックが入ってフリーズしました. 文字通りの意味でほんとよかったです.

就活イベントSクリア

志望した企業はどれも第一希望みたいなものだったので,このイベントはSクリアといっていいでしょう. ここから先は愚痴とか思ってたんと違うとことか

  • 4年のインターンで行った企業に就職する人が多いとか学校の説明会で聞いたけど全然そんなことなかった
  • ぼくの高専,あんまり就活に対していろいろサポートしてくれない
    • なんか情報出すのがいろいろ遅い
    • 自分から早めに準備する必要があった
  • 交通費やばい
    • インターンから最終面接まで1社あたり4回くらい企業に行かなきゃいけない
    • 春休みとかは週一で東京行ってた
    • バス移動安定
    • 交通費だけでPC買えそう
  • エントリシートの受付フォームの出来
    • カンマ,ピリオド禁止とか意味分からんが
  • エントリーシートは提出日より余裕をもって書き上げたほうがいい
    • それはそう
  • 寮生は就活がとてもしづらい
    • 門限が決まっているので朝早く出発,夜遅く帰宅するだけでも書類の提出が必要
  • 学校で書かせる就職に関する書類がめんどい
    • 公欠届けとか就職試験報告書を書かないといけない
    • ネットでできるようにしてくれ.そもそも書類処理するところが紙媒体大好きなことがいけない
  • 就職活動に時間さきたくない
    • 家で開発してたい
  • 面接は意外と楽しい(選んだ企業が自分に合っていれば)
  • 東京のゲーセンでメンテの良い台でプレイできる
  • バスタ新宿近くのはなまるうどん助かる
    • お腹が弱いので
  • 合同説明後に食ったラーメンうまかった
  • "就活"とか"面接"とか"エントリーシート"とかそういう系を含んだツイートをすると 高確率で変なアカウントにヒョローされる

編集雑記

過去に書いた就活スケジュールとか確認してたらエモくなってしまった. この記事書くのに2時間半くらいかかってるんだけどもっと作文力あげたい.

学校の休講補講情報をSlackに送ってみた話

こんばんは.nanaminです.

今回はプログラミングネタです.

読み返したら英単語とかカタカナの登場率がすごくて引いてる.でも固有名詞とか用語とかだからしょうがないです.

事の経緯

休講や補講の情報は学校のHPに掲載されるのですが,いちいち見に行くのも面倒.さらに教授が口頭でお知らせする場合もあるので,休講や補講の把握はかなり億劫でした.

そこで,休講補講情報をSlackに通知するWebアプリケーションを作ろうとなりました.あと最近Railsをやり始めてなにか作ってみたかったというのもあります.

結果

べんり〜

f:id:Nanami0634:20190529005627p:plain
休講補講情報がSlackにpostされた様子
f:id:Nanami0634:20190529101152p:plain
補講情報が前日にリマインドされる様子

材料

開発に使ったものたち

  • Web Application FrameworkとしてRuby on Rails (5.2)
  • Web ScrapingするためにNokogiri
  • 全角半角変換用にNKF
  • RubyでSlack APIを扱えるSlack Ruby Client
  • 公開用サーバーとしてHeroku
  • Heroku上で定期実行するためのHeroku Scheduler

実装方法

まずはリポジトリへのリンクを貼っておきます(結論優先オタク)

github.com

概要

とりあえず,処理の流れから

  1. 休講補講情報が載っているページをNokogiriでScrapingする
  2. データベースへ保存して,前回Scrapingしたときとの差異をチェック
  3. 差異部分をSlackのチャンネルにpost
  4. また休講or補講日の前日にもリマインド用としてSlackにpost

定期実行するため, 1〜3と4をrakeタスクとしてまとめておきます

Scraping部分

ここが一番肝だったりする.なぜなら半角と全角が混在しているから...

僕の学校の休講補講情報は,1つのtable要素で1つの休講or補講情報を表示していました.そのため,ページにある全table要素に対して,全てのtd要素の内容を取得しています.Nokogiriくんべんり.

doc = Nokogiri::HTML(open(scrape_url))
doc.css('table').each { |node|
  table = Nokogiri::HTML(node.to_xhtml)
  table_values = table.css('td').map { |node| node.content }
}

また,休講補講情報のフォーマットがガバガバ 多様性にあふれ全角数字と半角数字が混在していたので,NKFを使って半角に変換します.

# 全角英数字を半角英数字,全角スペースを半角スペース,半角カナを全角カナに変換
# さらに先頭と末尾の空白を除去
converted = NKF.nkf('-wZ1X', scraped_str).strip

あとはいつも通りデータベースとやり取りするだけです.

Slack用delivery_methodの実装

Slackへメッセージを送るには,Slack APIchat_postMessageメソッドを使います. Scrapingする処理層でメッセージを送る処理を書いてもいいですが,それだと芸がないのでActionMailerを通して行うようにしてみます.

実装にあたって,以下のサイトがとても参考になりました.ありがとうございます. tech.unifa-e.com

delivery_methodは,ActionMailerのなかでmailメソッドを使ったときに呼ばれるものです. ここでメッセージの内容を受け取ってSlackに送信する処理を記述します.

class SlackMessageDeliveryMethod
  def initialize(value)
    self.settings = value
  end

  def deliver!(message)
    attachments = JSON.parse(message.body.to_s)
    channel = message['channel']&.value || self.settings[:default_channel]
    
    client = Slack::Web::Client.new(token: self.settings[:api_token])
    client.chat_postMessage(
      channel: channel,
      attachments: [attachments],
      as_user: true
    )
  end
end

Slack用delivery_methodを登録

実装したdelivery_methodをActionMailer::Baseに登録します. ちなみに登録するとxxx_settingsというメソッドが自動で定義されるので,そこで初期化時のパラメータ(トークンなど)を渡しておきます. トークンを公開すると誰でもSlackにメッセージを送れるようになってしまうので,環境変数を使って隠蔽しましょう.

ActionMailer::Base.add_delivery_method(:slack_message, SlackMessageDeliveryMethod)

ActionMailer::Base.slack_message_settings = {
  api_token: ENV['SLACK_API_TOKEN'],
  default_channel: ENV['SLACK_DEFAULT_CHANNEL'],
}

送りたいメッセージを作成する

あとは,送りたいメッセージの内容を作成してmailメソッドを呼び出すだけです. 僕はruby側でjson形式のデータを作成し,それをviewに埋め込むだけにしています.

class LectureMailer < ApplicationMailer
  default delivery_method: :slack_message

  def new_info(lecture)
    @attachments_json = {
      fallback: '新しい休講補講情報です',
      color: 'good',
      pretext: '新しい休講補講情報です',
      fields: to_attachment_fields(lecture),
    }.to_json

    mail
  end

  def to_attachment_fields(lecture)
    # 講義情報をSlack APIの引数のフォーマットに変換する
  end
end

rakeタスクを作成

Heroku Schedulerで定期実行してもらうために,

  • Scrapingして変更があった情報をSlackに通知
  • 休講or補講日の前日にSlackにリマインド

の2つの処理を行うrakeタスクを作成します.

実装した2つのrakeタスクはこんなかんじ.

namespace :lecture do
  task scrape_and_send: :environment do
    before_time = Time.zone.now
    url = ENV['SCRAPE_URL']
    class_name = ENV['TARGET_CLASS_NAME']

    service = ScrapeLecture::WithUrlService.new(url)
    service.execute!

    created = Lecture.where(
      class_name: class_name, created_at: before_time..Time.zone.now
    )
    updated = Lecture.where(
      class_name: class_name, updated_at: before_time..Time.zone.now
    )
    updated = updated.reject { |i|
      i.created_at == i.updated_at
    }

    # slackのメッセージレイアウトの都合上,1件ずつ送信
    created.each { |info| LectureMailer.new_info(info).deliver_now }
    updated.each { |info| LectureMailer.update_info(info).deliver_now }
  end

  task send_reminders: :environment do
    now = Time.zone.now
    class_name = ENV['TARGET_CLASS_NAME']

    canceled = Lecture.where(
      class_name: class_name, canceled_from: now..now.since(1.days)
    )
    supplemented = Lecture.where(
      class_name: class_name, supplemented_from: now..now.since(1.days)
    )

    canceled.each { |info| 
      LectureMailer.canceled_reminder(info).deliver_now
    }
    supplemented.each { |info|
      LectureMailer.supplemented_reminder(info).deliver_now
    }
  end
end

Heroku Schedulerで定期実行

HerokuではアドオンとしてHeroku Schedulerというものが用意されています. これを使うことで,指定した時間ごとに設定したコマンドを実行してくれます.

インストールやrakeタスクの登録方法はこちらで紹介されています. インストールにはクレジットカード登録済みのアカウントが必要ですが,基本的に無料で使えます.とてもべんり devcenter.heroku.com

さっきのrakeタスクを登録するとこのような画面になりました.

f:id:Nanami0634:20190530145059p:plain
Heroku Schedulerでrakeタスクを登録したところ

感想

Heroku Schedulerたすかる

Webアプリケーションって手軽にそれっぽいものつくれて公開できるから良い.

Hello World!

はじめての人ははじめまして.nanaminです.

今日からブログをはじめます.

プログラムを書いたり,音楽ゲームをしたりするのが好きです.

のんびり書いていこうと思うのでよろしくお願いします.