この記事は、SYSKEN Advent Calendar 2023 12月24日の記事です。
はじめに
皆さん、こんにちは、後輩が優秀すぎてビビっている赤石匠です。
今夜はクリスマスイブですね。私は今夜も明日も誰かと過ごす予定がないのでMinecraftをしていると思います。
今回私は、SYSKEN Advent Calendar 2023の大トリを任されました。任されたからにはいいものを作りたいと思い、早めに準備を始めました。
本題
私はオセロをプレイして詰みになったとき、石(駒)がある形になる置き方を探してくれるプログラムを作りました。
最初は、プログラムが石を置いている様子が見れたらいいなと思い、UnityをC#言語で動かしていました。
しかし、数時間実行しても終わりません。どうやら、Unityでオセロの盤面を動かしながら、形を探すのはC#言語では少ししんどかったようです。
次に、Unityで実行することを諦め、さらに、C#言語より処理の早いと噂のC++言語でプログラムを書き直して実行しました。
すると、処理速度が数倍ほど早くなりました。
しかし、実行中の様子を見ていましたが、実行が終わるのに10年以上かかりそうでした。
結局、オセロで形ができる置き方を探すプログラムは諦めて、全く別のプログラムを作ることにしました。
そしてできたものが、メイク10です。メイク10というのは、ある数を一桁ずつにばらして、並び替えて、四則演算(足す+、引く-、掛ける*、割る/)と括弧()を使って10を作る。というゲームです。
例えば、56132だと(6-5+1)*(3+2)=10となりますね。
これをプログラムにやってもらおうと思いました。
こちらが、今回書いたメイク10をやってくれるプログラムです。
クリックしてプログラムを見る
#include <iostream> #include<vector> #include<algorithm> using namespace std; vector<int>v_symbol; vector<int>v_brackets; bool symbol(vector<float>v, int size) { bool b = false; int n = v.size() - 1; if (n == 0) { if (v[0] == 10) { return true; } else { return false; } } vector<float> rev(n); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (j < i) rev[j] = v[j]; else if (j == i) rev[j] = v[j] + v[j + 1]; else rev[j] = v[j + 1]; } b = symbol(rev, size); if (b) { bool b1 = false; for (int j = size - 2; j > i; j--) { v_symbol[j] = v_symbol[j - 1]; } v_brackets[size * 2 - 1] = v_brackets[size * 2 - 3]; for (int j = size - 2; j > i; j--) { v_brackets[j * 2 + 1] = v_brackets[j * 2 - 1]; v_brackets[j * 2 + 2] = v_brackets[j * 2]; v_brackets[j * 2 - 1] = 0; v_brackets[j * 2] = 0; } v_symbol[i] = 0; if (n > 1) { for (int j = i + 1; j < size - 1; j++) { if (v_brackets[j * 2 + 1] == 0) { if (v_symbol[j] >= 2) { b1 = true; } } else { break; } } for (int j = i - 1; j >= 0; j--) { if (v_brackets[j * 2 + 2] == 0) { if (v_symbol[j] >= 2) { b1 = true; } } else { break; } } if (b1) { v_brackets[i * 2]++; v_brackets[i * 2 + 3]++; } } return true; } for (int j = 0; j < n; j++) { if (j < i) rev[j] = v[j]; else if (j == i) rev[j] = v[j] - v[j + 1]; else rev[j] = v[j + 1]; } b = symbol(rev, size); if (b) { bool b1 = false; for (int j = size - 2; j > i; j--) { v_symbol[j] = v_symbol[j - 1]; } v_brackets[size * 2 - 1] = v_brackets[size * 2 - 3]; for (int j = size - 2; j > i; j--) { v_brackets[j * 2 + 1] = v_brackets[j * 2 - 1]; v_brackets[j * 2 + 2] = v_brackets[j * 2]; v_brackets[j * 2 - 1] = 0; v_brackets[j * 2] = 0; } v_symbol[i] = 1; if (n > 1) { for (int j = i + 1; j < size - 1; j++) { if (v_brackets[j * 2 + 1] == 0) { if (v_symbol[j] >= 2) { b1 = true; } } else { break; } } for (int j = i - 1; j >= 0; j--) { if (v_brackets[j * 2 + 2] == 0) { if (v_symbol[j] >= 2) { b1 = true; } } else { break; } } if (b1) { v_brackets[i * 2]++; v_brackets[i * 2 + 3]++; } } return true; } for (int j = 0; j < n; j++) { if (j < i) rev[j] = v[j]; else if (j == i) rev[j] = v[j] * v[j + 1]; else rev[j] = v[j + 1]; } b = symbol(rev, size); if (b) { for (int j = size - 2; j > i; j--) { v_symbol[j] = v_symbol[j - 1]; } v_brackets[size * 2 - 1] = v_brackets[size * 2 - 3]; for (int j = size - 2; j > i; j--) { v_brackets[j * 2 + 1] = v_brackets[j * 2 - 1]; v_brackets[j * 2 + 2] = v_brackets[j * 2]; v_brackets[j * 2 - 1] = 0; v_brackets[j * 2] = 0; } v_symbol[i] = 2; return true; } for (int j = 0; j < n; j++) { if (v[j + 1] != 0) { if (j < i) rev[j] = v[j]; else if (j == i) rev[j] = v[j] / v[j + 1]; else rev[j] = v[j + 1]; } } b = symbol(rev, size); if (b) { for (int j = size - 2; j > i; j--) { v_symbol[j] = v_symbol[j - 1]; } v_brackets[size * 2 - 1] = v_brackets[size * 2 - 3]; for (int j = size - 2; j > i; j--) { v_brackets[j * 2 + 1] = v_brackets[j * 2 - 1]; v_brackets[j * 2 + 2] = v_brackets[j * 2]; v_brackets[j * 2 - 1] = 0; v_brackets[j * 2] = 0; } v_symbol[i] = 3; return true; } } return b; } int main() { bool b; string s; while (1) { cout << "\"fin\"と入力すると終了します。" << endl; cout << "数字を入力してください: "; cin >> s; if (s == "fin") { return 0; } int ns = s.size(); int n = ns, is = 0; for (int i = 0; i < ns; i++) { if (s[i] - 0 < '0' - 0 || s[i] - 0 > '9' - 0) { n--; cout << s[i]; } } if (n != ns) { cout << "を削除しました。" << endl; if (n == 0) { cout << "数字がありませんでした。" << endl; continue; } } vector<float> v(n); v_symbol = vector<int>(n - 1); v_brackets = vector<int>(n * 2); for (int i = 0; i < n - 1; i++) { v_brackets[i * 2] = 0; v_brackets[i * 2 + 1] = 0; v_symbol[i] = -1; } for (int i = 0; i < ns; i++) { if (s[i] - 0 >= '0' - 0 && s[i] - 0 <= '9' - 0) { v[is] = s[i] - '0'; is++; } } if (n != ns) { for (int i = 0; i < n; i++) { cout << v[i]; } cout << endl; } sort(v.begin(), v.end()); do { b = symbol(v, n); if (b) break; } while (next_permutation(v.begin(), v.end())); if (b) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < v_brackets[i * 2]; j++) { cout << "("; } cout << v[i]; for (int j = 0; j < v_brackets[i * 2 + 1]; j++) { cout << ")"; } if (v_symbol[i] == 0) cout << "+"; else if (v_symbol[i] == 1) cout << "-"; else if (v_symbol[i] == 2) cout << "*"; else if (v_symbol[i] == 3) cout << "/"; } cout << v[n - 1]; for (int i = 0; i < v_brackets[n * 2 - 1]; i++) { cout << ")"; } cout << "=10" << endl; } else { cout << "10を作れない" << endl; } } }
長いですね。
遊び方説明
このプログラムを実行すると
"fin"と入力すると終了します。 数字を入力してください:
と表示されます。
指示の通りに好きな数字を入力するとプログラムが答えを出してくれます。
入力した数字で10を作れないときは
10を作れない
と表示されます。
終了したい時は
fin
と入力すれば終了できます。
実際に遊んでみる
今日は、12月24日なので1224で10を作ってみましょう。
答えが出ましたね。
次は、数字以外の文字や記号も入力してみます。
文字と記号だけが勝手に削除され、数字だけが残り、答えを出してくれました。
実際に遊んでみたい人は、VisualStudioでコンソールアプリの開発環境を立ち上げ、プログラムをコピペするか、こちらのリンクを開くと遊ぶことが出来ると思います。
リンク先のオンラインコンパイラは入力を一度しかできないので少しプログラムを修正しています。
終わりに
最初に作ろうとしていたものとは、全く関係の無いものを作ってしまいましたが、個人的になかなかいいものができたと思っています。
今回、載せることのできなかったオセロのプログラムも、書き直して最適化を目指すつもりです。
これでSYSKEN Advent Calendar 2023は終わります。
皆さん、また来年会いましょう!メリークリスマス!そして、良いお年を!!
コメントを残す