KotlinのDouble型
はじめに
本記事ではKotlinのDouble
型の仕様に関して確認したことをまとめます.
等価演算子
import kotlin.Double.Companion.NaN fun main() { println(NaN == NaN) // false println(NaN != NaN) // true println(NaN as Any == NaN) // true println(NaN as Any != NaN) // false println(0.0 == -0.0) // true println(0.0 as Any == -0.0) // false }
Kotlinの等価演算子は両辺が静的にDouble
型であるときはIEEE 754に従います.
そのため,NaN == NaN
はfalse
となります.
また,NaN != NaN
はtrue
となります.
しかし,NaN as Any == NaN
は左辺がAny
型であるため,equals
メソッドによってtrue
となります.
また,NaN as Any != NaN
は左辺がAny
型であるため,false
となります.
同様に,0.0 == -0.0
はIEEE 754に従ってtrue
となりますが,0.0 as Any == -0.0
はequals
メソッドによってfalse
となります.
関係演算子
import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf import kotlin.Double.Companion.NaN fun main() { println(NaN < NaN) // false println(NaN > NaN) // false println(NaN < pInf) // false println(NaN > pInf) // false println(NaN < nInf) // false println(NaN > nInf) // false println(NaN <= NaN) // false println(NaN as Comparable<Double> <= NaN) // true println(-0.0 < 0.0) // false println(-0.0 as Comparable<Double> < 0.0) // true }
Kotlinの関係演算子は両辺が静的にDouble
型であるときはIEEE 754に従います.
そのため,右辺または左辺がNaN
であるときは,関係演算子の結果はfalse
となります.
また,-0.0 < 0.0
はfalse
となります.
しかし,NaN as Comparable<Double> <= NaN
は左辺がComparable<Double>
型であるため,compareTo
メソッドを用いて判定され,結果はtrue
となります.
同様に,-0.0 as Comparable<Double> < 0.0
は左辺がComparable<Double>
型であるため,compareTo
メソッドを用いて判定され,結果はtrue
となります.
四則演算
import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf fun main() { // plus println(pInf + 1.0) // Infinity println(nInf + 1.0) // -Infinity println(pInf + pInf) // Infinity println(pInf + nInf) // NaN println(nInf + nInf) // -Infinity // times println(pInf * pInf) // Infinity println(pInf * 2.0) // Infinity println(pInf * 0.0) // NaN println(pInf * -0.0) // NaN println(pInf * -2.0) // -Infinity println(pInf * nInf) // -Infinity println(nInf * pInf) // -Infinity println(nInf * 2.0) // -Infinity println(nInf * 0.0) // NaN println(nInf * -0.0) // NaN println(nInf * -2.0) // Infinity println(nInf * nInf) // Infinity // minus println(pInf - 1.0) // Infinity println(nInf - 1.0) // -Infinity println(pInf - pInf) // NaN println(pInf - nInf) // Infinity println(nInf - pInf) // -Infinity println(nInf - nInf) // NaN // div println(pInf / pInf) // NaN println(pInf / 2.0) // Infinity println(pInf / 0.0) // Infinity println(pInf / -0.0) // -Infinity println(pInf / -2.0) // -Infinity println(pInf / nInf) // NaN println(pInf / pInf) // NaN println(2.0 / pInf) // 0.0 println(0.0 / pInf) // 0.0 println(-0.0 / pInf) // -0.0 println(-2.0 / pInf) // -0.0 println(nInf / pInf) // NaN println(pInf / nInf) // NaN println(2.0 / nInf) // -0.0 println(0.0 / nInf) // -0.0 println(-0.0 / nInf) // 0.0 println(-2.0 / nInf) // 0.0 println(nInf / nInf) // NaN }
KotlinのDouble
型の演算でオーバーフローが発生する場合は演算の結果はInfinity
となります.
アンダーフローが発生する場合は演算の結果は-Infinity
となります.
また,Int
型の除算と異なり,Double
型の除算では割る数が0.0
であっても例外が発生しません.
pow
import kotlin.math.pow import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf import kotlin.Double.Companion.NaN fun main() { // a^0.0 == 1.0 println(0.0.pow(0.0)) // 1.0 println(NaN.pow(0.0)) // 1.0 println(pInf.pow(0.0)) // 1.0 println(nInf.pow(0.0)) // 1.0 // a^1.0 == a println(0.0.pow(1.0)) // 0.0 println(NaN.pow(1.0)) // NaN println(pInf.pow(1.0)) // Infinity println(nInf.pow(1.0)) // -Infinity // a^Infinity println(pInf.pow(pInf)) // Infinity println(2.0.pow(pInf)) // Infinity println(1.0.pow(pInf)) // NaN println(0.5.pow(pInf)) // 0.0 println(0.0.pow(pInf)) // 0.0 println((-0.0).pow(pInf)) // 0.0 println((-0.5).pow(pInf)) // 0.0 println((-1.0).pow(pInf)) // NaN println((-2.0).pow(pInf)) // Infinity println(nInf.pow(pInf)) // Infinity // a^-Infinity println(pInf.pow(nInf)) // 0.0 println(2.0.pow(nInf)) // 0.0 println(1.0.pow(nInf)) // NaN println(0.5.pow(nInf)) // Infinity println(0.0.pow(nInf)) // Infinity println((-0.0).pow(nInf)) // Infinity println((-0.5).pow(nInf)) // Infinity println((-1.0).pow(nInf)) // NaN println((-2.0).pow(nInf)) // 0.0 println(nInf.pow(nInf)) // 0.0 // a^b (a < 0.0) println((-2.0).pow(2.0)) // 4.0 println((-2.0).pow(2.5)) // NaN println((-2.0).pow(3.0)) // -8.0 }
NaN.pow(0.0)
はNaN
ではなく1.0
,1.0.pow(pInf)
および1.0.pow(nInf)
は1.0
ではなくNaN
,(-2.0).pow(pInf)
,nInf.pow(pInf)
および(-0.5).pow(nInf)
はNaN
ではなくInfinity
,pInf.pow(nInf)
はNaN
ではなく0.0
となりました.
これらはJavaのMath.pow
の規定に合致するものですが私の直感に反するものだったため気をつけなければいけないと感じました.
log
import kotlin.math.log import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf fun main() { println(log(pInf, pInf)) // NaN println(log(2.0, pInf)) // 0.0 println(log(1.0, pInf)) // 0.0 println(log(0.5, pInf)) // -0.0 println(log(0.0, pInf)) // NaN println(log(-0.0, pInf)) // NaN println(log(pInf, 2.0)) // Infinity println(log(2.0, 2.0)) // 1.0 println(log(1.0, 2.0)) // 0.0 println(log(0.5, 2.0)) // -1.0 println(log(0.0, 2.0)) // -Infinity println(log(-0.0, 2.0)) // -Infinity println(log(pInf, 0.5)) // -Infinity println(log(2.0, 0.5)) // -1.0 println(log(1.0, 0.5)) // -0.0 println(log(0.5, 0.5)) // 1.0 println(log(0.0, 0.5)) // Infinity println(log(-0.0, 0.5)) // Infinity }
Kotlinのlog
に関して,特に気になる結果はありませんでした.
リファレンス
学年割り電卓2のリリース
学年割り電卓2(スマホ用Webアプリ)をすぐに使ってみる --> https://jumpaku.github.io/GakunenWari/
はじめに
日本には「先輩は後輩よりも偉い」という意味不明の謎の文化があるらしい. 実際,私も大学生活において次のような場面に遭遇したことがある.
- サークル内でお喋りをしていたとき,後輩が先輩に対して敬語を使わなかったため空気が張り詰めた.
- サークルで食事をして割り勘をするときに,先輩が後輩よりも多く支払った.
ここで,2. のように先輩の支払額が後輩のものよりも多くなるように割り勘することを学年割りという. 学年割りは学年が上がるに従って支払額も増加させる必要があるが,暗算だけで「丁度良い」増加量を設定するのは困難である. そこで,これまでに学年割り電卓 GakunenWari Calculator - Jumpaku’s blog[1],学年割電卓に新機能 GakunenWari Calculator updated - Jumpaku’s blog[2]が開発され,学年割りを行うスマホ用Webアプリによって,暗算に頼らない学年割りが実現された. しかし,これらのスマホ用Webアプリでは「丁度良い」増加量を見つけるために,学年間の支払金額の差をテキストフィールドに入力し,計算ボタンを押す,という作業を繰り返しながら試行錯誤する必要があり,手間がかかった. また,端数の処理していなかったため,学年割り計算後の集金にも手間がかかった.
以下では,端数処理を含めた学年割り計算法を示した上で,これを[1], [2]に組み込み,新たに「学年割り電卓2」を開発する.
端数処理を含めた学年割り計算法
学年割りは学年\(i \ (i \in I, I = \{0, \ldots, 6\})\)が上がるに従ってその学年の参加者一人当たりの支払額\(x_i\)が増加するように\(x_i\)を計算するものである. ただし,学年\(i\)は以下のように定める.
学部1年 | 学部2年 | 学部3年 | 学部4年 | 修士1年 | 修士2年 | 博士以上 |
---|---|---|---|---|---|---|
\(0\) | \(1\) | \(2\) | \(3\) | \(4\) | \(5\) | \(6\) |
ここでは\(x_i\)を単調増加する等差数列として求めることとする. また,切捨て端数の上限を\(u\)を設定し,\(x_i\)に次の制約を与えることとする.
$$ \forall i \in I, \ x_i は u で割り切れる. $$
この端数処理より,\(x_i\)が切りの良い値となり,集金の際の手間が軽減される.
合計支払金額を\(T\),学年が\(i\)である参加者の人数を\(c_i\)とし, 参加者からそれぞれ\(x_i\)だけ集金しそれを合計した合計集金額を \( T' = \sum_{i \in I} x_i c_i \) とするとき, 端数処理によって必ずしも \(T = T'\) とはならない. ここでは\(T'\)が\(T\)を超えない限り最大になるように\(x_i\)を求めて,不足額\(r = T - T'\)とともに出力するものとする.
\(x_i\)は初項\(x_0\),公差\(d\)を用いて
$$ x_i = x_0 + id $$
と表される. \(x_i\)は\(u\)の倍数となるため,\(x_0 = a u\),\(d = b u\)を満たすパラメータ\(a \in \mathrm{Z}\),\(b \in \mathrm{Z}\)が存在し,\(x_i\)は
$$ x_i = u(a + ib) $$
と表すことができる. 従って\(T'\)は\(n = \sum_{i \in I} c_i\),\(C = \sum_{i \in I} i c_i\)を用いて
$$ T' = u a n + u b C $$
と表すことができる. ここで,\(b\)は学年毎の金額差を調節するパラメータであり,ユーザはこれを変更することで丁度良い増加量を見つけることができる. また,\(a\)は初項を決定する未知のパラメータである.
\(r = T - T'\)より
$$ a = \frac{T - r - u b C}{u n} $$
と変形すると\(a\)が整数であり,\(T'\)は\(T\)を超えない限り最大となるため,
$$ r = (T - u b C) \% (u n) $$
と\(r\)が得られ,\(a\)が定まる.
以上より,
- 合計支払金額\(T\),
- 端数の上限\(u > 0\),
- 学年毎の金額差を調節するパラメータ\(b \geq 0\),
- 学年が\(i\)である参加者の人数\(c_i\)
を入力とし,
- 学年が\(i\)である参加者の一人当たりの支払額\(x_i\),
- 不足額\(r\)
を出力とする,端数処理を含めた学年割り計算法が実現される.
学年割り電卓2
上の端数処理を含めた学年割り計算法を用いてスマホ用Webアプリ「学年割り電卓2」を開発した. 学年割り電卓2はHTML,TypeScript,CSSを用いて開発され,現在GitHub Pages上で公開されている(https://jumpaku.github.io/GakunenWari/).
学年割り電卓2のUIを以下に示す.
まず,合計支払金額に\(T\)の値,切捨端数に\(u\)の値,それぞれの学年の人数に\(c_i\)の値を入力し, 次に,下部のスライダーを動かして\(b\)の値を設定すると, 支払額に\(x_i\)の値,不足額に\(r\)の値が表示される. ここで,\(b\)の値を設定するスライダーの変化に応じて,リアルタイムに支払額の表示が変化するため, 丁度良い増加量をすぐに見つけることができる.
また,表示される支払額は設定した端数の上限で割り切れることが保証されているため,集金時に細かい小銭をやり取りする手間もかからない.
学年割り電卓2のソースコードはGitHub - Jumpaku/GakunenWari: 学年割り電卓で公開されている.
まとめ
- 学年が上がるに従って支払額も増加する割り勘,すなわち,学年割りが行われる機会がある.
- 学年割りを暗算無しに行うためのスマホ用Webアプリ「学年割り電卓2(https://jumpaku.github.io/GakunenWari/)」を開発した.
- 学年割り電卓2は端数処理を行うため,それぞれ学年の参加者の一人当たりの支払額が切りの良い値となる.
- 学年間の金額差を設定するスライダーがあり,学年間の金額差を設定しやすい.
謝辞
本記事はMuroran Institute of Technology Advent Calendar 2018 - Adventarの記事です.
環境構築のためのDocker
はじめに
これはMuroran Institute of Technology Advent Calendar 2018 - Adventarの記事です.
- ホストマシンのOSはWindowsやmacOSを使いたい.
- Linuxも使いたい.(GUIは必要ない.)
- ホストマシンの環境をできるだけ変更したくない.
- 同じ開発環境を再現できるようにしたい.
- できれば賢い誰かが構築した環境を利用したい.
そんな時,ホストマシンにDockerをインストールしておくと,
- CUIだけの軽量なLinux仮想環境を構築できる.
- 環境構築の手順はテキストファイルに記述できる.
- そのファイルから開発環境を自動的に構築できる.
- Docker Hubにアップロードされた環境を利用できる.
なんて,素晴らしい.
インストール
それぞれのOSにおけるDockerのインストール方法を以下に示します.
Windows 10 64bit : Pro, Enterprise or Education
Install Docker Desktop on Windows | Docker Documentation
それ以外のWindows
macOS
Install Docker Desktop on Mac | Docker Documentation
Ubuntu
sudo apt install docker sudo apt install docker-compose
Docker
Dockerはイメージをもとにコンテナを生成し,コンテナ内の環境でアプリケーションを実行します. イメージはアプリケーションとその実行環境の情報をまとめたもので,Docker Hubからpullしてきたり,Dockerfileから作成したりすることで用意します. コンテナはイメージを実体化したもので,実行中のアプリケーションの状態を保持します. Docker Hubは利用可能なイメージが集まったDockerのサービスです. Dockerfileはイメージを作成する手順を記述したテキストファイルです.
Docker Hubからpullしてきたり,Dockerfileから作成したりしたイメージは,ダウンロードしてきたり,ソースコードからビルドしたりしてSSDに保存したプログラムに例えることができると思います. また,イメージをもとに実体化され,実行されるコンテナは,SSDからメモリにロードされ実行されるプログラムに例えることができると思います.
dockerのコマンド
docker --help
: dockerのヘルプを表示する.docker build -t イメージ名 ディレクトリ
: 指定されたディレクトリ
のDockerfileから指定されたイメージ名
のイメージを作成する.docker run イメージ [コマンド]
: 指定されたイメージ
を基にコンテナを起動し,コンテナ内で指定されたコマンド
を実行する.docker stop コンテナ
: 指定された実行中のコンテナ
を停止する.docker ps
: 実行中のコンテナ一覧を表示する.docker images
: ホストマシンにあるイメージ一覧を表示する.docker rm コンテナID
: 指定されたコンテナID
を持つコンテナを削除する.docker rmi イメージID
: 指定されたイメージID
を持つイメージを削除する.
Dockerfile
Dockerfileはイメージを作成する手順を記述したテキストファイルで,以下のように記述します.
# 基にするイメージを指定する.Docker Hubから探してくることが多い. FROM ベースイメージ # 作業ディレクトリを指定する. WORKDIR /workdir/path # ホストマシンのファイルやディレクトリをコンテナ内に複製する. COPY host/path/ container/path # Shellコマンドを実行する.アプリケーション実行のための準備を行う. RUN shell command # コンテナ実行時に実行されるアプリケーション実行コマンドを指定する. CMD ["アプリケーション実行コマンド", "コマンドライン引数1", "コマンドライン引数2", ...]
使用例
Hello World
次のコマンドを実行すると,
docker run hello-world
dockerはホストマシンに保存されているhello-world
イメージからコンテナを生成し,Hello Worldを出力するアプリケーションをコンテナ内で実行します.
ホストマシンにhello-world
イメージがないときは,dockerはDocker Hubからhello-world
イメージをpullしてきてホストマシンに保存します.
Bash
次のコマンドを実行すると,
docker run -i -t ubuntu bash
dockerはホストマシンに保存されているubuntu
イメージから(無いときはDocker Hubからpullして保存する.)コンテナを生成し,コンテナ内でBashを実行します.
-i
, -t
オプションはホストマシンのの標準入出力とコンテナの標準入出力を繋いぐためのオプションです.
C++
次の内容のファイルを用意します.
- ./Dockerfile
FROM ubuntu WORKDIR /home/app COPY ./src/main.cpp /home/app RUN apt update -y && apt upgrade -y && apt install -y g++ RUN g++ -o main main.cpp CMD ["./main"]
- ./src/main.cpp
#include<iostream> int main(int argc, char *argv[]) { std::cout << "hello docker-cpp" << std::endl; }
次のコマンドを実行すると,
docker build -t docker-cpp ./
カレントディレクトリのDockerfile
からdocker-cpp
という名前のイメージが作成されホストマシンに保存されます.
docker-cpp
は具体的にはDockerfile
に従い以下のように作成されます.
- ubuntuのイメージをダウンロードする.
- 作業ディレクトリを
/home/app
に設定する. apt update -y && apt upgrade -y && apt install -y g++
を実行し,アプリケーションのビルドの準備をする.g++ -o main main.cpp
を実行し,アプリケーションをビルドする.- コンテナ起動時に
./main
というコマンドでアプリケーションを実行するように設定する.
イメージ作成後に次のコマンドを実行すると,
docker run docker-cpp
ホストマシンに保存されたdocker-cpp
という名前のイメージからコンテナが生成された後に./main
が実行されて次の実行結果が得られます.
hello docker-cpp
Docker Compose
Docker Composeはdocker-compose.ymlに記述された設定に従って,1つ以上のコンテナを連携させて起動するものです. docker-compose.ymlはコンテナ起動時の設定を記述するテキストファイルです.
docker-composeのコマンド
docker-compose --help
: docker-composeのヘルプを表示する.docker-compose build
:docker-compose.yml
に従ってイメージを作成し,保存する.docker-compose up [-d]
:docker-compose.yml
に従ってコンテナを起動する.-d
オプションを付けるとコンテナをバックグラウンドで実行する.docker-compose run コンテナ名 コマンド
:コンテナ名
を持つコンテナを起動し,コンテナ内でアプリケーションの代わりにコマンド
を実行する.docker-compose exec コンテナ名 コマンド
:コンテナ名
を持つ起動中のコンテナ内でコマンド
を実行する.docker-compose stop
: 起動したコンテナを停止する.
docker-compose.yml
# docker-compose.ymlのバージョンを指定する.'3'を指定する. version: '3' # コンテナごとの設定を記述する. services: コンテナ名: # コンテナの名前をコンテナ名に設定する. container_name: 'コンテナ名' # imageまたはbuildでコンテナのイメージを指定する. # イメージを直接指定するときはimageで指定する. image: 'イメージ' # イメージをDockerfileで指定するときはbuildで指定する. build: # Dockerfileがあるディレクトリを指定する. context: 'Dockerfileのディレクトリ' # Dockerfileのファイル名を指定する. dockerfile: 'Dockerfile名' # ホストマシンのディレクトリをコンテナにマウントする. volumes: - 'ホストマシンのディレクトリ:コンテナのディレクトリ' # ホストマシンのポートを開放し,コンテナのポートに接続する. ports: - 'ホストマシンの開放ポート:コンテナの開放ポート' # コンテナ起動時に実行されるコマンドを指定する. command: ["コマンド", "コマンドライン引数1", ... ]
使用例
Python
次のファイルを用意します.
- ./docker-compose.yml
version: '3' services: docker-py: container_name: 'docker-py' image: 'python:3' working_dir: '/home/app' volumes: - './app:/home/app' command: ["python", "main.py"]
- ./app/main.py
print("hello docker-py")
次のコマンドを実行すると,
docker-compose up
カレントディレクトリのdocker-compose.yml
の設定に従って,docker-py
という名前のコンテナが起動し,次の実行結果が得られます.
hello docker-py
docker-py
は具体的にはdocker-compose.yml
に従い以下のように起動されます.
- python:3のイメージをダウンロードする.
- 作業ディレクトリを
/home/app
にする. - ホストマシンの
./app
をコンテナの/home/app
にマウントする. - コンテナを起動して
python main.py
を実行する.
また,次のコマンドを実行して,
docker-compose run docker-py bash
コンテナ内でpython
を実行するとPythonが対話モードで起動します.
Gnuplot
次のファイルを用意します.
- ./Dockerfile
FROM ubuntu WORKDIR /home/files COPY ./files /home/files RUN apt update -y && apt upgrade -y && apt install -y gnuplot CMD ["gnuplot", "plot-cos.plt"]
- ./docker-compose.yml
version: '3' services: gnuplot: build: context: './' dockerfile: 'Dockerfile' container_name: 'gnuplot' volumes: - './files:/home/files/'
- ./files/plot-cos.plt
set terminal pdfcairo set output 'plot-cos.pdf' set xrange [-2*pi:2*pi] set yrange [-1.5:1.5] set samples 500 plot cos(x)
- ./files/plot-sinc.plt
set terminal pdfcairo set output 'plot-sinc.pdf' set xrange [-10*pi:10*pi] set yrange [-1:1.2] set samples 500 plot sin(x)/x
次のコマンドを実行すると./files/plot-cos.pdf
が生成されます.
docker-compose build docker-compose up
次のコマンドを実行して,
docker-compose build docker-compose run gnuplot bash
コンテナ内でgnuplot ./plot-sinc.plt
を実行すると./files/plot-sinc.pdf
が生成されます.
PHP
次のファイルを用意します.
- ./docker-compose.yml
version: '3' services: docker-php: container_name: 'docker-php' image: 'php:7.2-apache' volumes: - './html:/var/www/html' ports: - '8080:80'
- ./html/index.php
<?php echo "hello docker-php" ?>
次のコマンドを実行して,
docker-compose up -d
ブラウザでhttp://localhost:8080
にアクセスするとhello docker-php
と表示されます.
まとめ
- DockerとDocker Composeを利用すると,ホストマシンのOSに依らずに,再現性のある軽量な仮想Linux環境を自動的に構築できます.
- Dockerはイメージからコンテナを実体化し,アプリケーションを実行します.
- Docker Composeはdocker-compose.ymlの設定に従ってコンテナを起動します.
- Dockerfileにはイメージの作成手順を書き,docker-compose.ymlにはコンテナ起動時の設定を書きます.
世界と孤独の説法(エピローグ)
説法系推理アドベンチャシリーズ外伝
ゲーム情報
本ゲームは登場人物の説法を聞くことと,論理クイズを組み合わせた説法系推理アドベンチャシリーズの外伝の推理リンクノベルです.
- タイトル : 世界と孤独の説法(エピローグ)
- 読み : せかいとこどくのえぴろーぐ
- 作者 : Jumpaku
- ジャンル : 説法系推理リンクノベル
- プレイ時間 : 30分程度
- プラットフォーム : PDFビューア
- リリース : 2018年4月22日
- 言語 : 日本語
- 開発環境 : LaTeX
経緯
第9回LOCAL学生部総大会 ヤバい同人誌執筆しようぜというイベントに参加しました.
これはOSC Hokkaidoや技術書展への出展を目指して,LaTeXで同人誌を書くというイベントでした. LaTeXはテキストファイルをPDFファイルに変換する組版システムです. LaTeXはチューリング完全であるため,どんなアルゴリズムでも実装できます. そこで,ゲームを作りたいと思いました. ただ,正直,LaTeXでプログラムを書きたくはないし,インタラクティブなゲームを作るビジョンも浮かばないため, 実際にはリンク機能だけを利用したノベルゲームを作成しました. 一応,技術要素として
- LaTeX によってノベルゲームを作成すること,
- プログラミングによって効率的に論理クイズを解くこと
がコンセプトとなっています. 物語は説法系推理アドベンチャシリーズ
- 愛と血の修羅場(サスペンス) jumpaku.hatenablog.com
- 恋と友情の常識(ファイト) jumpaku.hatenablog.com
- 罪と幸せの四苦八苦(ノアズアーク) jumpaku.hatenablog.com
の外伝となっています. 個人的には,外伝のように後からストーリーが追加される形式を好まないのですが, イベント期間が睡眠,食事を含めて31時間と短いため,全く新しい物語を考えるのではなく,外伝という形式にしました.
このイベントの成果物はLOCAL学生部の「情報ボーイズの寄稿ノート」にまとめられ,技術書展4で紙媒体で頒布されます.
当然,紙媒体ではリンク機能を使えないのですが,これを考慮していなかったため,技術書展4で購入しても本ゲームをプレイできないという事態が発生しました. 本ゲームをプレイするにはPDFファイルを手に入れる必要があります. 「情報ボーイズの寄稿ノート」のソースファイルはGitHubのリポジトリにあります.
ここからクローンしてきて,コメントアウトを解除してPDFにコンパイルすればプレイできますが, 手間がかかります. そこで,私の章だけをコンパイルしたPDFを用意しました.
世界と孤独の説法(エピローグ)_v1.pdf - Google ドライブ
「情報ボーイズの寄稿ノート」には私の他にもたくさんの著者がいて, それぞれが自分の得意分野の技術記事を書いています. 是非,そちらも読んでください.
リンク
- 第9回LOCAL学生部総大会 ヤバい同人誌執筆しようぜ https://connpass.com/event/74025/
- 愛と血の修羅場(サスペンス) https://jumpaku.hatenablog.com/entry/2016/04/14/002437
- 恋と友情の常識(ファイト) https://jumpaku.hatenablog.com/entry/2016/07/24/032632
- 罪と幸せの四苦八苦(ノアズアーク) https://jumpaku.hatenablog.com/entry/2017/07/24/044918
- 技術書展4 情報ボーイズの寄稿ノートhttps://techbookfest.org/event/tbf04/circle/14720002
- GitHub hyoiutu/techbookfest_localstudents_2017 https://github.com/hyoiutu/techbookfest_localstudents_2017
- 本ゲームをコンパイルしたPDF https://drive.google.com/open?id=1sDJou37nh-sm2PvUP6e-kcsKhzhu1WHE
室工ドライブ Drive around Muroran-IT
"安全第一"
概要
本ゲームは室蘭工業大学(室工大)の周囲を安全にドライブするゲームです. 室工大の周囲には路上駐車,道路を横断する歩行者などの様々な障害があります. ドライバはこれらの障害を避けながら安全に室工大を一周します.
情報
- タイトル : 室工ドライブ
- 読み : むろこうどらいぶ
- 作者 : Jumpaku
- ジャンル : カーアクション
- プレイ時間 : 1分程度
- プラットフォーム : macOS
- リリース : 2018年2月26日
- 言語 : 日本語
- 開発環境 : Unity
- バージョン : 1.1
遊び方
MurokouDrive_v1.app
を実行します.- 設定ウィンドウが開くので解像度,画質を設定します.
Play
ボタンを押してゲームを起動します.START
ボタンを押してゲームを開始します.- 反時計回りに道路を進みます.
- 運転に使用するキーは以下の通りです.
- アクセルを踏む:上矢印
- バックする:下矢印
- ハンドルを右に切る:右矢印
- ハンドルを左に切る:左矢印
- 道路から外れるとGame Overです.
- 室工大を反時計回りに一周するとClearです.
ダウンロード
実行ファイルは以下のリンクからダウンロードできます.
室工ドライブ_v1-1.zip - Google ドライブ
ソースコード
ソースコードは以下のリンクから参照できます. https://github.com/Jumpaku/MurokouDrive
開発
前からUnityに興味があり,今回初めてUnityで3Dゲームを作ってみました. 3Dモデル,当たり判定,当たり処理は既存のものを使いました. 工夫した点として,逆走を防ぐためにプッシュダウンオートマトンで状態を管理している点,地形や建造物をできるだけ実物に忠実に作成した点が挙げられます. 現在はmacOS向けのものしかリリースしてません.