Arrow Judgeをインストールして社内プログラミングコンテストを開催する

# 1. はじめに

社内に競技プログラミング部を作ってはどうだろう。互いに問題を投稿し合い、切磋琢磨していくような環境にならないだろうか...。そんなことを漠然と考えていると、タイミング良く「社内イベントを企画せよ」との指示が。というわけで、競技プログラミング形式でのプログラミングコンテストを、思い切って開催してみることにしました。

# 2. どうやったか

そのようなシステムってどうやって作るのだろう？と検索していると、以下の資料にたどり着きました。

- YouTube：[ICT Challenge+R2013 高校版 作品名「コマンド5つで構築できるオープンソースのオンラインジャッジシステム」](https://www.youtube.com/watch?v=oBL6wMwdywA)
- SlideShare：[Arrow Judge](https://www.slideshare.net/hiromu1996/arrow-judge)

目を通していて胸が熱くなりました。

- オンラインジャッジシステムを簡単にホスティングできる
- ユーザが自由に問題を追加できる
- クローズドなコンテストも開催できる
- 入力可能なプログラミング言語を追加できる

求めていたシステムがすでに提供されている！しかもオープンソースで！早速インストールして数人で利用してみると、反応は上々。これはいけそうだ。（長くなるので、Arrow Judgeのインストール手順は後述します）

# 3. どうなったか

数ヶ月のテスト運用の後、実際に社内プログラミングコンテストを開催してみました。

- 業務終わりの時間に開始したにもかかわらず、開発者の半数近くが参加した
- 最終的に、参加者全員が全問に解答した（未解答問題が残った人は、終了時間を過ぎてもチャレンジを続けた）
- 実施後に他の人の解答（ソースコード）を参照することで、技術的なコミュニケーションが生まれた
- アンケートには以下の声
 - 競技プログラミング形式でのプログラミングコンテストは良かった
 - 参加して良かった 再度開催されたらまた参加したい

そこには、問題を解くたびに達成感が得られ、さらに夢中になって取り組むという好循環がありました。また、開発者同士が相互に気づきを与え合う、学びの場となっている実感を得られました。

それからしばらく経ちましたが、実はまだ、競技プログラミング部の設立には至っていません。結局のところ、問題の良し悪しが成功の鍵を握るので、コンテストの問題を考えることがネックとなりました。

そこで、現在は[Project Euler](https://projecteuler.net/)の利用を考えています。すでにProject Eulerの問題を解いている開発者もいるので、コンテストを開催することはできませんが、Arrow Judgeにはコンテストだけでなく、常時、掲載された問題へ解答を投稿できる機能もあります。そこへProject Eulerの問題を掲載しておくことで、新入社員の研修、アルゴリズムの学習、他プログラミング言語の習得などに活用していくことができそうだと考えています。

以下、Arrow Judgeの参考画面です。

#### 問題一覧

![Problems.png](https://qiita-image-store.s3.amazonaws.com/0/60193/ea5102c2-f54e-bf99-767f-5748764ba6a7.png)

#### 問題

![Problem.png](https://qiita-image-store.s3.amazonaws.com/0/60193/f762a151-40d6-b44c-4d4f-385e290d547f.png)

#### 解答（ソースコード）入力

![Input.png](https://qiita-image-store.s3.amazonaws.com/0/60193/38836c65-ea64-1b29-0b6b-9ec39564570f.png)

#### 評価結果一覧

![Submissions.png](https://qiita-image-store.s3.amazonaws.com/0/60193/d9a53ef9-658e-1a1c-3269-afc081e0ed11.png)

# 4. インストール

ここからはArrow Judgeのインストール手順などを書いていきます。

サーバ環境は[Ubuntu 12.04 LTS Desktop 日本語 Remix](https://www.ubuntulinux.jp/News/ubuntu1204-desktop-ja-remix)を利用しました（記事の最後に、Ubuntu14.04へのインストールについても追記しました）。また、IPアドレスは 192.168.2.10 であるとしています。

※Linux関連の知識はほとんどなく、検索しながら進めた内容になります。最適でない可能性がありますので、間違いなどありましたら、お知らせいただけると嬉しいです。

## 4.1. 事前準備

### リポジトリの追加

Arrow Judgeをapt-getでインストールできるよう、リポジトリを追加しておきます。

```
$ sudo apt-add-repository ppa:hiromu1996/arrow-judge
$ sudo apt-get update
```

## 4.2. Webサーバの準備

### [arrow-judge-web](https://github.com/hiromu/arrow-judge-web)のインストール

まず、Arrow JudgeのWebサーバ機能[^1]を担う、arrow-judge-webのインストールを行っていきます。arrow-judge-webの動作にはApache、MySQL、PHPが必要となるので、LAMPサーバーをインストールします。

[^1]: 問題の掲載、解答（ソースコード）の投稿、評価結果（正解/不正解）の表示などを行う

```
$ sudo apt-get install tasksel
$ sudo tasksel install lamp-server
```

その後、arrow-judge-webをインストールします。

```
$ sudo apt-get install arrow-judge-web
```

### データベースの準備

続いて、ユーザ情報や問題などを管理するデータベースを作成します。MySQLへrootでログインし、データベース名、ユーザ名、ユーザパスワードなどを指定します。（以下の例では、データベース名：arrow_judge、ユーザ名：judge、ユーザパスワード：xxxxとしていますが、適宜変更して構いません）

```
$ mysql -u root -p
> CREATE DATABASE arrow_judge DEFAULT CHARACTER SET utf8;
> CREATE USER 'judge'@'localhost' IDENTIFIED BY 'xxxx';
> GRANT ALL PRIVILEGES ON arrow_judge.* TO 'judge'@'localhost';
> FLUSH PRIVILEGES;
> quit
```

また、インストールされたデータベースの初期化スクリプトを修正しておきます。/usr/share/arrow-judge/app/Config/database.sql 内の以下の部分で\`users\`を\`testcases\`へ変更します。

```diff:database.sql.diff
--- database.sql	(revision x)
+++ database.sql	(working copy)
@@ -331,8 +331,8 @@
 --
 
 LOCK TABLES `testcases` WRITE;
-/*!40000 ALTER TABLE `users` DISABLE KEYS */;
-/*!40000 ALTER TABLE `users` ENABLE KEYS */;
+/*!40000 ALTER TABLE `testcases` DISABLE KEYS */;
+/*!40000 ALTER TABLE `testcases` ENABLE KEYS */;
 UNLOCK TABLES;
 
 --
```

### arrow-judge-webの設定

ここからは、ブラウザを利用しての設定となります。

#### ディレクトリ所有権

ブラウザから http://192.168.2.10/judge/ へアクセスし、表示された各ディレクトリの所有者をsudo chown -hR www-dataで変更します。

```
$ sudo chown -hR www-data /usr/share/arrow-judge/app/Data/Answer/
$ sudo chown -hR www-data /usr/share/arrow-judge/app/Data/Output/
$ sudo chown -hR www-data /usr/share/arrow-judge/app/Data/Testcase/
$ sudo chown -hR www-data /usr/share/arrow-judge/app/tmp/
$ sudo chown -hR www-data /usr/share/arrow-judge/app/Plugin/HtmlPurifier/Vendor/HtmlPurifier/library/HTMLPurifier/DefinitionCache/Serializer
```

その後「Recheck」を押すと、ボタン名が「Install」に変化し、以下のようになります。

![DirectoryPermissionStatus.png](https://qiita-image-store.s3.amazonaws.com/0/60193/4016514f-63a3-40bf-5e35-a36793ba13de.png)

これ以降も、ブラウザに表示された指示に従い、先に作成したデータベース情報や、SMTPサーバ情報などを入力していけばOKです。

#### データベース

![DatabaseSetting.png](https://qiita-image-store.s3.amazonaws.com/0/60193/d0b66096-5d4c-077a-7962-b7e495393ca3.png)

#### SMTPサーバ

![EmailSetting.png](https://qiita-image-store.s3.amazonaws.com/0/60193/8b6a795a-6009-d832-3776-96212ee241c5.png)

#### 管理者アカウント

![CreateAdministrativeAccount.png](https://qiita-image-store.s3.amazonaws.com/0/60193/ed4e48e0-dd5f-2ef3-a5c3-881e80f3c91e.png)

#### トップページ表示内容

![InstallationWasFinished.png](https://qiita-image-store.s3.amazonaws.com/0/60193/06bde0f5-3398-5c9f-0657-f6710c84bfe1.png)

## 4.3. ジャッジサーバの準備

### [arrow-judge](https://github.com/hiromu/arrow-judge)のインストール

次は、ジャッジサーバ機能[^2]を担う、arrow-judgeをインストールします。本来は、複数のサーバへインストールし、分散処理できるようになっているのですが、簡単のためWebサーバと同一環境へインストールしました。

[^2]: 投稿された解答（ソースコード）のコンパイルと実行、実行結果の評価などを行う

```
$ sudo apt-get install arrow-judge
```

途中でWebサーバのURL入力が必要となるので、http://192.168.2.10/judge と指定します（最後に/をつけない）。

![ArrowJudgeWebSystem.png](https://qiita-image-store.s3.amazonaws.com/0/60193/04b10a53-c056-c7b4-1955-f715ff4ca01b.png)

### ジャッジサーバの有効化

インストールが完了するとWebサーバから認識されます。先ほど設定した管理者アカウントでWebサーバへログインし、上部に表示されている「Site Config」からジャッジサーバを有効化します（Enableをクリック）。

![JudgeServerSettings.png](https://qiita-image-store.s3.amazonaws.com/0/60193/3ad0b71a-9810-3ac4-57d6-7981d2888c0d.png)

### x86対応

利用した環境が32bitだったので、スクリプトの修正が必要でした。

```
$ sudo /etc/init.d/arrow-judge stop
```

で、arrow-judgeを停止してから、/usr/lib/python2.7/dist-packeges/arrow-judge/\_\_init\_\_.py 内の以下の部分で'/lib64'を削除し、

```__init__.py.diff
--- __init__.py	(revision x)
+++ __init__.py	(working copy)
@@ -2,5 +2,5 @@
 
 AVAILABLE_DEVICES = ['full', 'null', 'random', 'stderr', 'stdin', 'stdout', 'urandom', 'zero']
 CGROUP_SUBSETS = ['cpuacct', 'memory']
-AVAILABLE_PATHS = ['/bin', '/etc', '/lib', '/lib64', '/proc', '/sbin', '/usr/bin', '/usr/include', '/usr/lib', '/var/lib']
+AVAILABLE_PATHS = ['/bin', '/etc', '/lib', '/proc', '/sbin', '/usr/bin', '/usr/include', '/usr/lib', '/var/lib']
 SYSCTL_PARAMS = ['kernel.sem=0 0 0 0', 'kernel.shmall=0', 'kernel.shmmax=0', 'kernel.shmmni=0', 'kernel.msgmax=0', 'kernel.msgmnb=0', 'kernel.msgmni=0', 'fs.mqueue.queues_max=0']
```

再度、arrow-judgeを起動します。

```
$ sudo /etc/init.d/arrow-judge start
```

### コンパイラの追加

Webサーバへ解答（ソースコード）を投稿する際、初期設定では C（gcc）、C++（g++）が選択できるようになっています。どちらも利用できるようにするため、ジャッジサーバへg++をインストールしておきます。

```
$ sudo apt-get install g++
```
以上で、準備は完了です。問題を作成し、プログラミングコンテストライフをお楽しみください。

# 5. 運用

## 5.1. arrow-judgeの起動、停止

起動と停止は以下で行えます。

```
$ sudo /etc/init.d/arrow-judge start
$ sudo /etc/init.d/arrow-judge stop
```

起動後、/var/log/arrow-judge/judge.logに

> started with pid xxx

と表示されていない場合は正常に起動していないので、起動後に確認すると良いと思います。

## 5.2. arrow-judgeの設定

設定ファイルは/etc/arrow-judge/server.confにあります。

# 6. 注意

作成したコンテストは削除できないようです。また、公開後のコンテストへは問題を追加できないようです。

# 7. Ubuntu14.04へのインストール

[Ubuntu 14.04 LTS 日本語 Remix](https://www.ubuntulinux.jp/News/ubuntu1404-ja-remix)へのインストールをトライしてみました。上記の手順と異なる部分を記載します。

## 7.1. arrow-judge-web

### Apacheの設定

http://192.168.2.10/judge/ でArrow Judgeへアクセスできるよう、エイリアスの設定が必要です。（Ubuntu12.04ではconf.dディレクトリが存在していたので、インストール時に自動的に行われていました）

```
$ sudo cp /etc/arrow-judge/apache.conf /etc/apache2/conf-available/arrow-judge.conf
$ sudo a2enconf arrow-judge
$ sudo service apache2 reload
```

### CakePHPテンプレートを修正

/usr/share/arrow-judge/app/View 以下にあるCakePHPテンプレートファイルを、いくつか修正する必要があります。すでにPull requestされていますので、以下を参照して対応（「<?」を「<?php」へ変更）してください。（Ubuntu12.04ではとくに対応しなくても問題ありませんでした）

[Use long tags in PHP #4](https://github.com/hiromu/arrow-judge-web/pull/4)
[Use long tags in PHP #5](https://github.com/hiromu/arrow-judge-web/pull/5)

## 7.2. arrow-judge

64bit環境を利用する場合、上記[x86対応](https://qiita.com/hideo-works/items/cb8c7a8c4d177be1c08d#x86%E5%AF%BE%E5%BF%9C)は不要です。