ラリコン試作1号でラリーした話
奈良でラリってきました(言い方)
「ミステリーラリー」という誰でも参加できる超楽しいラリーです。 teamkomaren.amebaownd.com
今回はArduinoで自作したGPSラリコンを使ってみます。
怪しい雰囲気を醸し出しておる。
何があっても良いように四輪にしました。
ま、防水機能も無いしな…
ダム湖畔に佇む我が愛車
クイズを解きながら、奈良をぐるっと180kmぐらい走行。
柿の葉寿司うまいうまい
ソフトクリームうまいうまい
で、ラリーどうでした?
結果ですが、無事にゴールは出来ました。
成績的にはクイズの結果が・・・ぐぬぬ
あとむっちゃ暑かったのに、クルマだからと油断して帽子もタオルも持っていかなかったのは失敗^^; (←キモい顔文字)
次どうする
しかし、なーんか精度がイマイチで、iPhone12のGPSと比較すると4kmで100mぐらい、遅れる方向の誤差がでます。 これが計算誤差なのか、割り込み禁止区間がどこかに残ってるのか、そもそもタイマー割り込みの精度が悪いのか・・・
カジュアルラリーで使う分にはコマ毎に補正してやれば良いのでそんなに問題にならないのですが・・・わたし、気になります!
えるたそに言われては仕方ないので、とりあえず要調査
あと、GPSだから当然トンネル入った時に速度がわからなくなるのですが、トンネル出た時に何か処理して誤差補正やったほうが良いのか?コードを追加してまで補正する意味があるのか? みたいなところも課題です。
とりあえず、ATtiny44で作る予定の試作2号機で検討しようっと(←未来のオレにぶん投げ)
Arduboyで麻雀ゲーム作る話(3)~ 放浪編
ただでさえ月末月初で忙しいところに大連の発注先がコロナでロックダウン一歩手前になってしまったり、大学生の息子が帰省してきたり、ラリーに参加する準備をしてたり、うっかり韓国語の単語を暗記を忘れていたり、うっかり青いドゥカッティモンスター696+を見つけてしまったり、もう何が何やらみたいな状況なのですが、時間を見つけてプログラミングを進めています。
役判定を作らねば
さて、ここまででメンツが完成しているかどうかを判定するところまで作ったので、これからそれが役になっているかを判定するロジックを作ります。
最初は正規表現でズバッと解決しようと思っておったのですが、麻雀の役って改めて調べてみるとなかなかアナログで「いやだこれ、1パターンずつハードコーディングしたほうが早くない・・・?」みたいな感じです。
それだと個人的に面白くないので、なんかこうパターンマッチングできないかと試行錯誤して、
の2段構えで対処することにしました。
例えばみんな大好きタンヤオなんかは、一九字牌以外のメンツで構成されているので、中張牌メンツの定義を
define CHU ([TK][MPZ][2-8])|([S].[2-6])
としてやって、役そのものは
yaku TANYAO 1 'all CHU
なんて書いてやれればOKです。
わかりやすいように日本語に訳すと
みたいな感じですね。
別にyaku
で直接メンツ構成を書いても構いません。
yaku PINHU 1 'all (T[MPZ].)|(TFy)|(S..) #ただし両面待ち
→ピンフは1翻で全部のメンツが「萬筒索」の対子かオタ風の対子もしくは順子
・・・「両面待ちでアガったか」はハードコーディングするしかないかな~
それをどうするかというと「これら定義を元にCのソースを吐くpythonスクリプトを組む」のでした。
yacc&lexっぽいですね!
麻雀役だけに、麻雀ヤック・・・
そして一部組んだものがgithubにあります。
↓
github.com
ファイル | 説明 |
---|---|
yaku.ms | 役の定義をするスクリプトです |
yaku.py | yaku.msを食ってCソースを吐くpythonプログラムです |
yakutest.h | テスト用にgccに食わせる時に使うヘッダファイルです |
役判定仕様.md | yaku.msに記述するための定義仕様書 |
現状は本当に一部の役(しかも面前)しか想定してないです(←さすがに全部作るの大変かなあ・・・と諦めてきた^^;)
コマンドラインにて
#!/bin/bash cat yaku.ms | py.exe yaku.py > ptest.c gcc -fsyntax-only -w -DYKDEBUG ptest.c
などとしてやると、yaku.msを食ってptest.cを作って、gccでチェックしてくれます。
治具的なプログラムなので、エラーチェックがかなりいい加減なのもご愛嬌です。
さて次は
とりあえず、全部スクリプトを組んで、PCのコンソールアプリで役判定・点数計算できるとこまで開発しても良いかもしれません(デバッグが簡単なので・・・)。
Arduboy関係ないじゃん!という向きもあろうかと思いますが、最終的には乗せます故・・・
ATtiny44用の書き込みシールドを作った話
個人で会社を運営していると何から何まで自分でやらないといけないので、請求やら経理処理が大量発生する月末月初はとっても忙しいです^^;
ああ~ 忙しい忙しい・・・へあっ!?
お前は・・・
ATtiny44用書き込みシールド・・・
はっ! いつのまにかハンダゴテ握っていた、だとー!? (棒
信じられねーと思うが俺も何をされたかわからなかった・・・!
書き込みシールドとは
ま、冗談はさておき、書き込みシールドちゅのはATtiny44をいじるのに都度ブレッドボードを持って歩くのが大変邪魔くさいので、UNOのシールドにしたものです。
要はこの回路ですな↓
簡単なようで、配線間違えるとチェックがめんどくさい。
でもやっぱり簡単なシールドです。
わあ、ぴったり・・・!(←専用ボードだから当たり前)
※「waves Arduino 用 UNO プロトタイプ シールド ブレッドボード 付属」480円(現在欠品中)
https://www.amazon.co.jp/gp/product/B079FQD44P/
試してみる
できたら試してみます。 まずはLチカから
改めて調べてみたら、案外ATtiny44でのLチカ情報が少ないので、自分の備忘も兼ねてこちらに回路とプログラムをアップしときますね。
ATtiny44の右上のピン(PA5)でLチカします。
抵抗は1kΩ(Fritzingで設定忘れてます)
void setup() { pinMode(5, OUTPUT); // PA5 } void loop() { digitalWrite(5, HIGH); delay(1000); digitalWrite(5, LOW); delay(1000); }
この前試したLCDも繋いでみましょう。
↓ちなみに「この前」の記事 kikyujin.hatenablog.com
さて次は
ラリコンのソフトシリアルを使った作業を進めたい・・・
Arduboy麻雀のプログラムも進めたいし・・・
しかしまずは、事務仕事をやっつけねば・・・^^;
Arduinoでラリコン作る話(2)→ATtiny44でラリコン作る話(2)
Arduino UNOでGPS使った簡易ラリコンを作った話を「Arduinoでラリコン作る話」としてまとめようと思っていたんですが、ATtiny44が来ちゃったのでこっちに載せ替えることにしました。
ほら、現在進行系でハマってるほうが楽しいでしょ?
構成要素と方針
基本同じです(ATtiny44+GPSモジュール+LCD1602+スイッチボード)。
ただ、Arduino UNOよりGPIOが少ないので、LCDはI2Cで制御してみます(今回)。
しかし、ここにGPSのソフトウェアシリアルとかタイマー割り込みかけると結構CPU負荷高そうだけど大丈夫かな・・・
もしダメそうなら、またその時に対応考えます(泥縄式)
ちなみに、それぞれCPUの違いなどはこのページが詳しいです↓
Arduinoで作った回路の小型化(Arduino互換機の製作)(10) - しなぷすのハード製作記
まずはArduino UNOでLCD1602を動かしてみる
これまでは4bitパラレルで接続して表示させていたので、I2Cで動かすのは初めてです。
とりあえず、Arduino UNOを使って、ちゃんと動作するか確認します。
ライブラリは"liquidcrystal-i2c"を使います。
普通にIDEの スケッチ|ライブラリをインクルード|ライブラリを管理 からインストールしてやればOK。
www.arduino.cc
ソースは適当に拾ってコピペします(苦笑)
#include <LiquidCrystal_I2C.h> // I2C address 0x27 16x2 LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Hello world"); lcd.setCursor(0, 1); // キョウハイイテンキ lcd.print("\xb7\xae\xb3\xca\xb2\xb2\xc3\xdd\xb7"); } void loop() { }
Arduino UNOとの接続ですが、
- SDA→A4
- SCL→A5
としてあげれば良いようです(D4/D5ではありません!チューイせよ)
接続したらスケッチをコンパイルしてアップロード
簡単ですね!
ライブラリがいろいろ揃っていると本当に楽です。
はい!次行ってみよー!(cv.いかりや長介)
ATtiny44でもLCD1602を動かしてみる
さて本日のメインイベント。
ネット見てみたんですが、あんまりATtiny44でLCD1602動かしたみたいなページないんですよね・・・
ということはアレだ、むっちゃ簡単かむっちゃ難しいの2択だ!
多分むっちゃ簡単なんだろう(←楽観的)
まず配線ですが、ATtiny44の場合、
- SDA→PA6
- SCL→PA4
となっているようです(ピン配置などはここにデータシートがあります←ぶん投げ)。
スケッチの書き込みにはさっきのArduino UNOを使うので、ごちゃごちゃ配線する前にArduinoISPを書き込んでおかないと・・・ほらさっき試しにUNOで1602動かしたでしょ?
忘れるとハマりますよ!ハマるからね!ほらハマった!
配線は次のようにしました↓
で、ソースはどうなんだろう・・・
なんか、このままコンパイルしたら動く気がする・・・
ていうか、きっと動く!
ライブラリの中の人が設定とかいい感じにしてくれるに違いない!
じゃ、そのままコンパイル・・・の前に、ボードの設定をUNOからATtiny44にしないと・・・
忘れるとハマ(以下略)
こんな設定ですな。
じゃあコンパイルしてアップロード(「書き込み装置を使って書き込む」)。
SUGEEEEEEEEEE!!!
ほんとに動いた!
これ何気なく動いてますが、割りとスゴいことなんでは?
上位CPUのスケッチをコンパイルし直すだけで動かせるなんて・・・
本当にプロトタイピングに向いているんだな!Arduinoは!(富野話法)
次どうする?
今回表示が動いたので、最低限の情報が確認できるようになりました。
となればGPSモジュールを動かしてみるのになんの躊躇(ちゅうちょ)がありましょうか、いやない(反語)
ていうか、ソフトウェアシリアルがI2Cとバッティングしないのか?ちょっと心配^^;(←キモい絵文字)
ATtiny44/85にブートローダーを書き込んだ話
GPSラリコンを小型化しようと思って、秋月電子にATtiny44を注文しておいたのが届きました。
何かに使うかもと思ってついでにATtiny85も注文しておきました(何かって・・・)
左の14ピンのヤツがATtiny44、右の8ピンのヤツがATtiny85です。
で、ここが大事なのですが、コヤツらもArduino IDEでプログラムが作れます。
必要なものは、
あとブレッドボードとかジャンパーとか10μFの電解コンデンサとかLチカ用にLEDとか1kΩの抵抗とか・・・一般家庭に普通にあるもので大丈夫ですね。
準備するArduinoくんですが、実はプログラム書き込み機として使われます。
あとは電源とか・・・
まさに体目当てです。
準備しよう
いろんなサイトが紹介してくれています。
このあたりが絵が多くて親切でしょう。
また、このサイトはArduinoの種類と接続を詳しく説明してくれています。
ハマりポイント
一連のオペレーションの中に「ボードマネージャでボードを追加する」工程があるのですが、どのサイトを見ても
ArduinoIDEの環境設定で「追加のボードマネージャのURL」に"http://drazzy.com/package_drazzy.com_index.json"と入れて、ツール|ボード|ボードマネージャで"ATTinyCore"をインストールせよ
と澄ました顔でサラっと説明されています。 ところが、私がこれをやったらエラーが出てインストールできませんでした・・・↓
https://azduino.com/bin/micronucleus/micronucleus-cli-2.5-azd1b-i686-mingw32.zipのダウンロード時にエラーが発生しました java.lang.RuntimeException: java.lang.Exception: https://azduino.com/bin/micronucleus/micronucleus-cli-2.5-azd1b-i686-mingw32.zipのダウンロード時にエラーが発生しました at cc.arduino.contributions.packages.ui.ContributionManagerUI.lambda$onInstallPressed$2(ContributionManagerUI.java:179)
ぐぬぬ・・・と思いつつ、本家のGitHub
ATTinyCore/Installation.md at OldMaster---DO-NOT-SUBMIT-PRs-here-Use-2.0.0-dev · SpenceKonde/ATTinyCore · GitHub
を見てみますと、マニュアルでもインストールできると書かれています。
やっぱオートはダメだ!時代はマニュアルだ!
簡単にやり方だけ説明すると、
- ここんちからReleasesのLatestなzipをダウンロードするgithub.com
- IDEの環境設定にある「スケッチブックの保存場所」をみて、そこに「hardware」というフォルダを作る
- そこにさっきのzipを展開したフォルダを突っ込む(私の場合は"ATTinyCore-1.5.2"というフォルダでした)
そうすると、IDEのツール|ボードメニューにずらずらと対応するATtinyチップが出てきます
後は、諸先輩方の言うようにしてやればだいたいできると思います(ぶん投げ)
さてLチカ
ATtiny44
ATtiny85
こいつなのですが、最初こんな動作をしてまして「DQN車のハイフラッシャーか!?」と思って電源入れ直したら治ったという・・・まあ、そういうこともあるよねというお話
次はどうする?
ATtiny44ですが、これは冒頭でも書いたようにGPSラリコンに使おうと思っています(ワンボード化できるといいなあ・・・)
ATtiny85については、これを使ったArduboyっぽいプロダクトがありまして、なかなか趣深いので、この互換機でも作ろうかなあ・・・と思っています。
詳細はこちら↓
www.tinyjoypad.com - TINYJOYPAD_ATTINY85
日本語でも「ATtiny85 ゲーム」で検索すると、こちらの互換機を作られているサイトがいくつかあります。 ご参考までにm(_ _)m(←キモい顔文字)
Arduboyで麻雀ゲーム作る話(2)
今回は和了判定の一歩手前、メンツが完成しているかどうかの判定ロジックを作成しました。
なお、現在進行中でプログラムを書いているため、バグっているかもしれませんのでご注意ください。
データ定義
ラリコン作っている時に知ったのですが、実はAVRマイコンは8bitマイコンだったのでした。
つい「今どきふつーならintは32bitの16bitマイコンだろ?JK」と思い込んでいてハマってました^^;
ということはですよ、アセンブラちゃんと見てないので良くわかりませんが、レジスタの都合など考えると8bitで処理したほうが何かとお得なような気もします。
そこでプログラム中では
u8(unsigned char)
s8(signed char)
を多用しています。
オーバーフローに注意しましょうm(_ _)m
あと、牌については素直に
とコードするということで。
0~34なので、6bitで十分表せるということですな。
また、黙ってソートしてやれば理牌できるっちゅうことでもあります。
メンツ完成している?
さて、麻雀1。
麻雀は14枚2の牌で役を作るゲームです。
役は七対子や国士無双などの例外を除き、
にて構成されています。
最低限、この組み合わせになってないと役として成立しません。
ということは、まずは手牌がこの組み合わせになっているか調べる必要があります。
みんな大好き正規表現を使うと、
[TKS][TKS][TKS][TKS][TKS]
みたいな感じか?
ただし、対子は1つの役に1つしか現れません。
しかも都合が悪いことに、対子は牌2枚、刻子順子は牌3枚で構成されています。
素直に頭から読んでってもダメっちゅうことですな。
まあ、
111 222 333 44 555
みたいなヤツだと、
123 123 123 44 555
だったり、
123 11 234 234 555
11 123 234 234 555
だったりしますから、総当りするしか無さそうですね。
みんな大好きツリー構造図で書くと
となりますわな。
これが辿れれば成立、辿れなければ不成立ということで、簡単に再帰で書けそうです。
再帰で書くとメモリ食って遅いというイメージですが(そうでもない?)今回はたかだか最大5段程度のネストなので良いことにしましょう。
ちなみに昔私が買っていじってたPC-9801DXは12MHz駆動の80286CPUを搭載し、2.6MIPS程度の性能だったそうです(ちなみに318k円)。
こんなちっこいArduboyは16MHzのATmega32U4CPUを搭載して、16MIPSで動作するという、CISC/RISCの違いはあれど隔世の感がありますね・・・(←ジジィの昔話)
Anyway,
コーディングを始めましょう。
長いので構造のみこちらで。
// 解析中手牌 u8 g_analyze[TEHAI_NUM]; // 1メンツ判定 #define PI_ANALYZE_MAX 64 // 最大バッファ(最大126=0x7e) #define PI_LEAF 0x80 // 末端マーク #define PI_ROOT 0xff // ルートマーク u8 g_pindex[PI_ANALYZE_MAX]; // 解析結果 u8 g_piRoot[PI_ANALYZE_MAX]; // 親ノード保持 u8 g_bToitChk; // 対子チェック済みマーク u8 g_piLast; // g_pindexの末尾 bool recIndex (u8 root, u8 index) { ... } void initAnalyzeMent(const u8* pai = NULL) { ... } // 最大5段程度の再帰にしかならないので深度優先検索を採用します // root g_pindexに対するインデックス(初期値PI_ROOT) // now g_analyzeに対する牌解析位置(初期値0) bool analyzeOneMent (u8 root, u8 now) { if (now >= TEHAI_NUM) { // 1ルート探索終了 // 末端マーク g_piRoot[root] |= PI_LEAF; return true; } // 残り1枚か? if (now == TEHAI_NUM - 1) { // もはやメンツは作れない return false; } // 対子か?(対子は1解析セットに雀頭1つしかない) bool res = false; if (!g_bToitChk && isToit(now)) { // インデックス記録 if (!recIndex(root, PI_TOIT | PAI_KIND(g_analyze[now]))) { return false; } // 深度優先検索 g_bToitChk = true; if (!analyzeOneMent(g_piLast - 1, now + 2)) { // このルートは無い g_piLast--; // 記録を消す } else { // このルートで最後まで解析できた res = true; } // 探索を続ける g_bToitChk = false; } // 刻子か? if (isKot(now)) { // インデックス記録 if (!recIndex(root, PI_KOT | PAI_KIND(g_analyze[now]))) { return false; } // 深度優先検索 if (!analyzeOneMent(g_piLast - 1, now + 3)) { // このルートは無い g_piLast--; // 記録を消す } else { // このルートで最後まで解析できた res = true; } // 探索を続ける } // 順子か? if (now >= TEHAI_NUM - 2) { // 2枚組なので違う return res; } // そもそもMAN/PIN/SOUの1~7でないと駄目 if (!isShuntTop(now)) { return res; } // スタック節約のために分かりにくいループにしてあります // 2枚目を探す // 同じ数字は省く u8 p2, p3; for (p2 = now + 1;;) { u8 a = PAI_KIND(g_analyze[now]); u8 p = PAI_KIND(g_analyze[p2]); if (a == p) { if (++p2 >= TEHAI_NUM - 1) { // 残り牌が無い return res; } // else continue; } else { // a != p if (a + 1 == p) { break; // 三枚目を探す } else { // 順子ではない return res; } } } // 3枚目を探す // 同じ数字は省く for (p3 = p2 + 1;;) { u8 a = PAI_KIND(g_analyze[p2]); u8 p = PAI_KIND(g_analyze[p3]); if (a == p) { if (++p3 >= TEHAI_NUM) { // 残り牌が無い return res; } // else continue; } else { // a != p if (a + 1 == p) { break; // 順子だ } else { // 順子ではない return res; } } } // 順子だ // インデックス記録 if (!recIndex(root, PI_SHUNT | PAI_KIND(g_analyze[now]))) { return false; } // 面倒だけど牌を入れ替える swapPaiForShunt(now, p2, p3); // 深度優先検索 if (!analyzeOneMent(g_piLast - 1, now + 3)) { // このルートは無い g_piLast--; // 記録を消す } else { // このルートで最後まで解析できた res = true; } // 牌を戻す restorePaiForShunt(now, p2, p3); return res; }
ソースはgithubのmajan.inoにあります。
やっているのは、ツリーに沿って片っ端(左端)からこの牌が対子になるか、刻子になるか、順子になるかをチェックしているだけです。
そして、メンツになったならばg_pindex[]
というバッファに記録して、再帰で下層を探索に行きます。
ちょっとトリッキーなのは順子の探索でしょうか。 手牌はソートされている前提なので、
333444555
みたいな形がありえます。
そこで、同じ数牌はスキップしながら345という順子を見つけたならば、
345 334455
と強引に並べ替えて下層の探索に行き、帰ってきたら元の形(333444555)に戻しています!
まるで、80286のプロテクトモードからリアルモードに復帰してくるのにCPUリセットするようなノリで、インテルの人に
「なんと野蛮な・・・」
と呆れられてしまうことでしょう3。
動かしてみる
とりあえずできたんで、動かしてみます。
確認はデバッグシリアルを使いましょう。
じゃあ、サンプルにさっきの、
111 222 333 44 555
を使いましょう。
動かしてみると
と表示がされます。
おお、動いてる。 トシちゃんかんげきー(棒)
下の4行+1行が解析結果です。
S1S1S1T4K5 S1T1S2S2K5 K1K2K3T4K5 T1S1S2S2K5 4pattern
彼が言ってることを翻訳すると、
123-123-123-44-555
123-11-234-234-555
111-222-333-44-555
11-123-234-234-555
の4パターン
ということですね。確かに合ってます。
const unsigned char test_tehai[]
をいじって他のパターンも試してみましょう。
111 222 333 44 556
K1K2S3T3S4 K1K2T3S3S4 2pattern
111 222 333 44 557 だと
no ten
と、にべもなく回答してくれます。
まだバグっているかもしれません。
他にもいろいろ試してみましょう。
次どうする
ここまでできたら、ほとんどできたようなものです!(本当か?)
次は、役になっているかどうかの判定を作りたいと思っています。
ハードコーディングしてやれば簡単に実装できそうに思うのですが、それではあまり面白くないので別の(正規表現を使うとかそういった類の)アプローチが無いかな?と考えています。
しばしお時間をいただけますと幸いです。
Arduboyで麻雀ゲーム作る話(1)
Arduinoに小さいディスプレイと十字+ABボタンつけた製品?があります。
その名もArduboy。
名刺より小さいですね!
昔、キックスターターで購入して、ちょっと遊んで打ち捨ててあったのですが、これが持ち歩くのにちょうど良くて、仕事部屋でもダイニングでも出張先でもArduinoプログラムができてしまう優れものだと気が付きました。
んじゃ、なんか作るか (←いつもどおり手段と目的を履き違えている)
それにしても小さいディスプレイ(1.3インチOLED 128x64)やの、ワレ
せや!この狭いとこに小さい牌を並べたら絶対ワシらの老眼では見えへんやろ!
ジジィ発見器に使えるし、麻雀作ったろ!
という軽いノリから作ることにして、ちょっとどこまで作りきれるかわかりませんが、できるところまでやってみようかと思っています。
イメージの準備
麻雀といえば和了に14枚の牌が必要1なので、横128ドットの液晶に並べるとすると最大幅で横9ドットになります。
牌と牌の間には仕切り線が欲しいので、中身は横8ドットで描くことになります。
高さはちょっと余裕があるので11ドットで描きます。
ドット絵作成は便利なサイトがあったので、こちらを使いました。
ミニドット絵メーカー3
またイメージはプログラム中に持つことになるので、Cの配列形式になっていると都合が良いです。
これまたArduboyに特化した便利なページがあったので、使わせてもらいました。
Image Converter
通常、ゲームに必要な麻雀牌は
の34種類2。 それに
- 牌の外枠(10x15dot)
を作成しました。 githubにgifファイルと.hファイルをまとめた.zipを放り込んでおきました。
プログラム
せっかくデータを作ったので、早速表示してみます。
Arduboyの開発には専用のライブラリが必要なのでインストールします。
このあたりが詳しいです↓
Arduboy
とりあえず表示できれば良いので、setupにいろいろ書きます。
void setup() { // initiate arduboy instance arduboy.begin(); // here we set the framerate to 10, we do not need to run at // default 60 and it saves us battery life arduboy.setFrameRate(10); // arduboy.clear(); arduboy.fillRect(0, 0, 128, 64); for (int i = 0; i < 9; i++) { arduboy.drawBitmap(i * 9, 0, img_back, 10, 15, BLACK); arduboy.drawBitmap(i * 9 + 1, 2, &img_manzi[i * 16], 8, 11, BLACK); } for (int i = 0; i < 9; i++) { arduboy.drawBitmap(i * 9, 14, img_back, 10, 15, BLACK); arduboy.drawBitmap(i * 9 + 1, 16, &img_manzi[(i+9) * 16], 8, 11, BLACK); } for (int i = 0; i < 9; i++) { arduboy.drawBitmap(i * 9, 28, img_back, 10, 15, BLACK); arduboy.drawBitmap(i * 9 + 1, 30, &img_manzi[(i+18) * 16], 8, 11, BLACK); } for (int i = 0; i < 4; i++) { arduboy.drawBitmap(128 - 36 + i * 9, 0, img_back, 10, 15, BLACK); arduboy.drawBitmap(128 - 35 + i * 9, 2, &img_manzi[(i+27) * 16], 8, 11, BLACK); } for (int i = 0; i < 3; i++) { arduboy.drawBitmap(128 - 36 + i * 9, 14, img_back, 10, 15, BLACK); arduboy.drawBitmap(128 - 35 + i * 9, 16, &img_manzi[(i+31) * 16], 8, 11, BLACK); } arduboy.display(); }
なお、
img_back
が牌の外形のイメージimg_manzi
が牌の中身イメージの配列(manziといいながら筒子から索子から何から全部突っ込んであります)
になります。
ちなみに8×11のイメージで16バイト使っているようです。11バイトでいいように思うんですが、なぜでしょう?
とりあえず動けば良いので、あんまり突っ込んで調べていません^^;(←キモい顔文字)
出力イメージはこちら↓
なお、Arduboyは本来白黒反転液晶なので、何もしないと黒バックに白文字になります。 個人的に見づらくてかなわんので、わざと白黒を逆転させています。
俺は黒白が好きだぜ!という人はソースコードの
arduboy.fillRect(0, 0, 128, 64);
を
arduboy.clear();
に(いまコメントアウトされてますね)、
また
arduboy.drawBitmap(ほにゃらら, BLACK);
となっているところを
arduboy.drawBitmap(ほにゃらら);
にしてあげてください(,BLACK
を削除する)。
次回、テンパイかどうかの判定ロジック(の前段階)を組みます。
というか、ここまではもう組んでいるのでアップするだけです!
その後はまだこれからなので、ぼちぼちやろうと思っています。
※解説なんかいらねーぜ!いま見せろって方は、上の表示部分含めてgithubにmajan.inoがあります。