#1.はじめに
皆さんはFizzBuzzという問題を聞いたことがあるでしょうか。
聞いたことがない方はQiitaにも記事がたくさんあるので見てみるといいでしょう。
僕はその問題を聞いたときにふと思ったのです。
「応用すれば世界のナベアツが作れそうだ」と。
作成する前にネットでも調べたところ、僕の思った以上にナベアツプログラムが溢れていたため、ここでは差別化するために初心者にも分かりやすく、かつ面白い出力にできるようにしています。
よろしければどうぞご覧になっていってください
#2.仕様(書き方含む)
- 【必須】「3で割り切れる」か「3の付く数字」の場合アホになる。
- 【ナベアツ】出力は顔文字で行い、アホの時は1回ごとに表情を変えさせる
- 【ナベアツ】デフォルト出力は数字、アホ出力は文字列の数字で行う。
- 【初心者用】単純なif文、for文のみで作成(三項演算子、switch、拡張for文などは一切使用しない)
- 【初心者用】importは行わない。
- 【初心者用】インデントは2段まで(ネストは一切使用しない)
- 【初心者用】メソッドチェーンを使用しない
- 【できれば】少しくすりとするようなネタコードを入れる
- 【妥協】基本的に数える数字は100までとする。
#٩( ᐛ ) さんっ!実装!
やはり、だらだらと過程を書くのはつまらないのでさくっと実装を載せます
public class World {
//アホな場合用セリフ配列
static final String[] AHO_NUMBER = { "", "いち", "に", "さん", "よん", "ご", "ろく", "なな", "はち", "きゅう" };
//今回使用するフォント(デフォルトとイタリック(斜体))
static final String DEFAULT = "\u001B[0m";
static final String ITALIC = "\u001B[3m";
//前回のアホの情報。一回ごとに表情を変えるため。
boolean isAhoContinuous = false;
//引数で渡された数字分、ナベアツが数字をコンソールに出力する。
void aho(int maxNumber) {
for (int number = 1; number <= maxNumber; number++) {
//引数で渡した数字が「3の倍数」か「3の付く数字」かをチェックする
//[アホ]=true //[アホじゃない]=false
boolean isAho = ahoCheck(number);
//処理が一瞬で終わってしまうの防ぐためスレッドスリープする。
stopTime(400);
//ナベアツに喋ってもらう
sayNumber(isAho, number);
}
//無事に終わったときの処理
stopTime(600);
System.out.println(" ᐠ( ᐛ )ᐟ く オモロー!");
}
private boolean ahoCheck(int number) {
//3桁の数字の場合、アホになのでナベアツは逃げる
//でも100は頑張って言う
if (number > 100) {
throw new NullPointerException("もう無理……");
}
//3の倍数かチェック
if (number % 3 == 0) {
return true;
}
//3の付く数字かチェック
//containsメソッドを使う為にString型に変換
String strNum = String.valueOf(number);
//数字に3がついていれば「true」を返す
if (strNum.contains("3")) {
return true;
}
//上記のどれでもない場合「false」を返す
return false;
}
private void sayNumber(boolean isAho, int number) {
if (isAho) {
//アホの場合
sayAhoNumber(number);
} else {
//真面目な場合
System.out.println(DEFAULT + "(`・ω・´)く " + number);
}
}
private void sayAhoNumber(int number) {
//アホ用の文字列数字を取得
String ahoNumber = getAhoNumber(number);
//前回のアホの状況に応じて顔の向きを変化
if (isAhoContinuous) {
System.out.print(DEFAULT + " ( ᐖ )۶ く ");
isAhoContinuous = false;
} else {
System.out.print(DEFAULT +" ٩( ᐛ ) く ");
isAhoContinuous = true;
}
System.out.println(ITALIC + ahoNumber + "っ!");
}
private String getAhoNumber(int number) {
//桁数を取得のためString型に変換
String strNum = String.valueOf(number);
//2桁の場合
if (strNum.length() == 2) {
//十の位の数字を取得
String ahoNum = getTenthPlaceNumber(strNum);
//一の位の数字を取得
char tmp = strNum.charAt(1);
int no = Character.getNumericValue(tmp);
ahoNum += AHO_NUMBER[no];
return ahoNum;
}
//1桁の場合
return AHO_NUMBER[number];
}
private String getTenthPlaceNumber(String strNum) {
//十の位の数字をint型で取得
char tmp = strNum.charAt(0);
int no = Character.getNumericValue(tmp);
String str = "";
//十の位が1の場合「じゅう」だけを返し、
//それ以外は「数字 + じゅう」と返す
if (no == 1) {
str = "じゅう";
} else {
str = AHO_NUMBER[no] + "じゅう";
}
return str;
}
private void stopTime(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {}
}
}
上記にはエントリポインタがないのでメインクラスも作成
public class Aho {
public static void main(String[] args) {
World nabeatsu = new World();
nabeatsu.aho(100);
}
}
というわけでナベアツの完成である。
実は初心者用ということで一クラスにまとめたかったのだが(メインは2行だけでアホにすらなれないし)、
けど、どうしてもこの一文が書きたかったのだ。もう仕方ない。
World nabeatsu = new World();
出オチ感はいなめない
#4.実行結果
というわけで、早速上記をそのまま実行してみる。
result
(`・ω・´)く 1
(`・ω・´)く 2
٩( ᐛ )く さんっ!
(`・ω・´)く 4
(`・ω・´)く 5
( ᐖ )۶く ろくっ!
~~中略~~
(`・ω・´)く 26
٩( ᐛ )く にじゅうななっ!
(`・ω・´)く 28
(`・ω・´)く 29
( ᐖ )۶く さんじゅうっ!
٩( ᐛ )く さんじゅういちっ!
( ᐖ )۶く さんじゅうにっ!
٩( ᐛ )く さんじゅうさんっ!
( ᐖ )۶く さんじゅうよんっ!
٩( ᐛ )く さんじゅうごっ!
( ᐖ )۶く さんじゅうろくっ!
٩( ᐛ )く さんじゅうななっ!
( ᐖ )۶く さんじゅうはちっ!
٩( ᐛ )く さんじゅうきゅうっ!
(`・ω・´)く 40
~~中略~~
(`・ω・´)く 98
٩( ᐛ )く きゅうじゅうきゅうっ!
(`・ω・´)く 100
ᐠ( ᐛ )ᐟく オモロー!
なかなかいい感じになったと思う。実際に実行していただけると分かるが、Thread.sleep(処理を指定時間止めるメソッド)を使用したり、アホの場合はイタリック(斜体)で表示されたりとコンソール上でも動きがあって結構面白い動きができているんじゃないだろうか。
#5.解説
##全体
まずは全体の感想として、少しばかり冗長になりすぎたかなという反省点。ネストを使用しない分メソッドが多くなったり、単純な書き方を意識するあまり、全体的に長くなってしまった。もう少し分かりづらくてもぎゅっと引き締めた方がむしろ初心者にとっても分かりやすいかも?
//containsメソッドを使う為にString型に変換
String strNum = String.valueOf(number);
//数字に3がついていれば「true」を返す
if (strNum.contains("3")) {
return true;
}
ここなんかは
if(number / 10 == 3 || number % 10 == 3) {
return true;
}
で、代用できたりする。わざわざString型に変換などしなくても後者の方が分かりやすかったんじゃないかと書き終わった後に気づいたが、前者は前者で仕様変更した場合三桁以上でも対応できたりするのでこのままにしておいた。
##流れ
初心者で「ちょっとコード長すぎてどこ見ていいか分かんないよー」って方向けに
プログラムの流れが分かりやすいよう、メインフローとなる部分を抜き出します
void aho(int maxNumber) {
for (int number = 1; number <= maxNumber; number++) {
//引数で渡した数字が「3の倍数」か「3の付く数字」かをチェックする
//[アホ]=true //[アホじゃない]=false
boolean isAho = ahoCheck(number);
//ナベアツに喋ってもらう
sayNumber(isAho, number);
}
ここでやっていることは
- for文で1から数字をインクリメントしながら繰り返し処理をします
- 現在の数字がアホになる数字(3の倍数か3が付く数字)かを判定します
٩( ᐛ )くさんっ! 2の判定に応じてコンソールに表示する文字を変化させます
この大きな流れさえ掴めれば、あとは細かいところを実装するだけです。
##遊び心(という名の妥協)
//3桁の数字の場合、アホになのでナベアツは逃げる
//でも100は頑張って言う
if (number > 100) {
throw new NullPointerException("もう無理……");
}
この部分。最初は何桁(int型の範囲)でも対応できるようにしようと思っていたのですが、これを実装しようとしたらこれ以上コードが長くなってしまって、もっと根本的な「初心者でも分かりやすく」が成り立たなくなってしまうことを危惧して諦めました。
もしこの記事を見て、自分で書いてみよう、と思われた方がいらっしゃいましたら、ぜひ何桁でも対応できるパターンも書いてみてください。
#( ᐖ )۶ ろくっ! 最後に
ここまでご覧いただきありがとうございます。
ふと思い立ったので書いてみたのですが、やはりこういった遊び心が溢れるプログラムは書いていて楽しいですね。