Skip to content

giver_guide

Alingof edited this page Dec 19, 2023 · 8 revisions

作問者ガイド

このページはJuggernautのgiver(出題者)向けチュートリアルです.

Juggernautの作問では主に3つのことをします.

  • ブレッドボード1枚に回路を組む.
  • ESP32に書き込むプログラムを作成する.
  • 問題文を作成する.

装置の構成

Juggrnautで使用する装置は下図のような構成になっています.

主にESP32や7セグLED,ボタン,ブザーなどがついた“制御部”(プリント基板で構成されている部分)とgiver(出題者)が問題を作る“競技部”(1枚のブレッドボード)に分かれています. 出題者も回答者も触ることができるのは,この“競技部”だけです.

上の図の例ですと“競技部”であるブレッドボードからはGND線と赤いワイヤ,青いワイヤだけが伸びています. このうちsolver(挑戦者)が触ることができるのはGND線を除いた赤と青のワイヤだけです.

問題を決める

まずはアイデアを出すところからです.
コンセプトを決めうちしたり,面白そうなセンサがあればそれを軸に考えたりすると良いでしょう.
ワイヤを切ったりボタンを押したり傾けたり振ったり暗くしたり温めたり……使う部品や構成を工夫すればかなり自由が効くはずです.

次に設定時間から難易度を考えてそこから部品の数やプログラムの複雑さを決めます. 単にスイッチ4つを使った問題でも配線を工夫すればかなり難しい問題になるでしょう.

作問に関する制約を公式レギュレーションから抜粋していくつか紹介しておきます.

  • giver(出題者)は装置を装置の制限時間の15%以内の時間で一度解除し動作を確認しなければならない(15%ルール)
    • 装置の制限時間が10分なら,giverは90秒以内に解除状態に持っていく必要があります.
    • 答えを知っている人なら確実に短時間で解ける問題にするため.考える時間も操作する時間もたくさん必要な問題を防ぐため.
  • 解除条件にランダムな要素を入れてはならない
    • プログラムで乱数を使って偶然の要素を入れるのは禁止.
  • 決められた数以上の部品・ワイヤを使用してはならない
    • 今回は特に指定はありませんが,規制をかける大会も面白いと思います.
  • 部品や配線の確認が困難になるような妨害行為の禁止
    • パテで埋めるなどの物理的な妨害は禁止です.
  • 極端にプログラムを長くする行為の禁止
    • プログラムの難読化の方面で難易度を上げるのは歓迎ですが,極端に長かったり道筋が不透明で難易度が滅茶苦茶なものは規制の対象になります.
  • 任意のタイミングでないと解けない問題の禁止
    • 内部の状態によらずn秒目でしか解けないという問題は禁止です.
    • もちろんすべてのflagを満たさないと解けないといったものはこの規制には当たりません.

レギュレーションに合致してそうなことを確認したら回路を組んでいきましょう.

回路の作成

実際に回路を組んでみます.

VCCとGNDは専用のピン(最初の写真の左端のピンソケット)から,I/OはESP32-DevKit-Cのピンから直接取ります. ESP32のピンアサインは以下のようになっています. https://github.com/bdring/FluidNC/wiki/images/dev_kit_pinout.jpg https://raw.githubusercontent.com/wiki/bdring/FluidNC/images/pin_ref.jpg ピンによっては全く使えない/入力しか使えないなど様々な条件があるため注意してください.

また,以下のピンは装置の制御のために使っているため競技部では使えません.

ピン番号 ピンに書かれている名前
GPI39 VP
GPI36 VN
GPIO25 25
GPIO26 26
GPIO27 27
GPIO12 12

ブレッドボードの配線にはハードワイヤを,装置へのピンの接続はソフトのジャンプワイヤを使うと分かりやすいでしょう.

プログラム

プログラムはArduino IDEを使って書きこみます.
サンプルはhttps://github.com/Alignof/Juggernaut/tree/master/example_src/Timerに置いてあります.
このディレクトリにはTimer.inocontrol.hcontrol.inoの3つのファイルがありますが,giverが触るのはプロジェクト名と同じTimer.inoだけです.
残りの2つは装置の制御用なので改変しないでください.

giverが書くコードは以下のようになっています.

#include "control.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"

//=============================================================================
//  START of giver code (copy the below code you wrote into the specification)
//=============================================================================

int time_limit = 300;

// giver pin assgin
const uint8_t NAVY_BUTTON  = 22;
const uint8_t WHITE_BUTTON = 18;
const uint8_t RED_BUTTON   = 19;
const uint8_t BLUE_BUTTON  = 23;

void setup_pin(void) {
	pinMode(NAVY_BUTTON, INPUT_PULLUP);
	pinMode(WHITE_BUTTON, INPUT_PULLUP);
	pinMode(RED_BUTTON, INPUT_PULLUP);
	pinMode(BLUE_BUTTON, INPUT_PULLUP);
}

void gaming(void *pvParameters) {
	bool flag1 = false;
	bool flag2 = false;
	bool flag3 = false;
	bool flag4 = false;

	while(1) {
		delay(1);
		flag1 = (digitalRead(NAVY_BUTTON) == LOW);
		flag2 = (digitalRead(WHITE_BUTTON) == HIGH);
		flag3 = (digitalRead(BLUE_BUTTON) == LOW);
		flag4 = (digitalRead(RED_BUTTON) == HIGH);

		// succeeded
		if(flag1 && flag2 && flag3) {
			succeeded();
		}

		// failed
		if(!flag4) {
			failed();
		}
	}
}

//=============================================================================
//  END of giver code
//=============================================================================

変数time_limitには問題の制限時間を秒単位ので設定してください.例では300秒なので5分です.
関数setup_pinには入出力に設定するピンの設定を書いてください.

関数gamingがmain関数のような役割をします.ここに成功/失敗の判定を書いていくことになります.
成功/失敗の判定はsucceeded関数とfailed関数に飛んだかで判定します.定義はcontrol.inoに書かれています.
succeeded関数に飛べばタイマが止まりランプが緑になります.つまりここがsolverの目指すゴールです.
failed関数に飛ぶとランプが赤になりブザーが鳴ります.

成功条件と失敗条件は必ず1つは設定しなくてはなりません.

問題文の作成

最後にgiverに与える問題文を書きます.

問題文には,

  • 装置名
  • 作問者
  • 作問日
  • 制限時間
  • 回路の写真(省略可)
  • 回路に用いた部品
  • 作成したプログラム

を書いてください.

これらを簡単にビルドできるテンプレートとdockerファイルを配布しています:https://github.com/Alignof/Juggernaut_spec_builder
以下のように書くことで簡単にpdfファイルを生成できます.

---
listings: True
codeBlockCaptions: True
---

\begin{table}[ht!]
    \centering
    \large
    \begin{tabular}{p{2cm}|p{13cm}} \hline
        装置名          & four buttons      \\\hline
        装置番号        & 000-001           \\\hline
        作問者          & Write your name   \\\hline
        作問日          & 2021 9/28         \\\hline
        制限時間        & 15m00s            \\\hline
    \end{tabular}
\end{table}

# 作問者より一言
この装置は練習問題となる基礎的な問題です.
ボタン4つから構成されているシンプルな作りになってます.  
落ち着いて配線とプログラムの関係が理解できれば解けることでしょう.


# 回路
回路の全体の写真を[@fig:circuit]に示す.

![回路全体の写真](./circuit.jpg){#fig:circuit}

また,回路に使用する部品の一覧を[@tbl:parts]に示す.

部品名          個数        データシート
------          ------      ------------
タクトスイッチ  4           [https://akizukidenshi.com/download/ds/switronic/1273HIM-160G-G.pdf](https://akizukidenshi.com/download/ds/switronic/1273HIM-160G-G.pdf)

: 回路に使用する部品の一覧 {#tbl:parts}

# ソースコード
[@lst:code]に競技に使用するソースコードを示す.
```{.cpp #lst:code caption="競技に使用するソースコード" title="timer.ino"}
// giver pin assgin
const uint8_t NAVY_BUTTON  = 22;
const uint8_t WHITE_BUTTON = 18;
const uint8_t RED_BUTTON   = 19;
const uint8_t BLUE_BUTTON  = 23;

int time_limit = 300;

void gaming(void *pvParameters) {
	bool flag1 = false;
	bool flag2 = false;
	bool flag3 = false;
	bool flag4 = false;
	while(1) {
		delay(1);
		flag1 = (digitalRead(NAVY_BUTTON)  == LOW);
		flag2 = (digitalRead(WHITE_BUTTON) == HIGH);
		flag3 = (digitalRead(BLUE_BUTTON)  == LOW);
		flag4 = (digitalRead(RED_BUTTON)   == HIGH);
		
		// succeeded
		if(flag1 && flag2 && flag3) {
			signal     = GREEN;
			timer_stop = true;
			while(1) delay(1e5);
		}

		// failed
		if(!flag4) {
			signal = RED;
			timer_stop = true;
			digitalWrite(BUZZER, HIGH);
			while(1) delay(1e5);
		}
	}
}
\```

大体同じフォーマットならどのようなツールで作成しても構いません.
問題文はsolverが書き込めるように紙で配布するのが望ましいですが,印刷が手間の場合電子的に配布しても良いでしょう.
その場合は別途メモを取れるような紙を用意すべきです.