こんにちは。先日入社した周(シュウ)です。
趣味は山登りで、休みの日は、緑の多い山で森林の匂いを嗅ぐのが好きです。
よろしくお願い致します。
「プログラミングの楽しさって何?」
と聞かれたら、やはり多種多様の手段です。
そのアルゴリズムを考え、悩みながら、答案を掘り出すことに楽しさがあります。
アルゴリズムを考えることで、
クリエイターにとって必要不可欠の思考力を鍛えることが期待できます。
特に、日本の伝統ゲームである「将棋」を再現するためのアルゴリズムは競い合いも出るほど、
プログラム学習者に人気があります。
同じ言語を使用しても、100人が記述したら、100通りの可能性が出てきます。
今回、私はJavaScriptを使って、将棋のアルゴリズムに挑戦してみました。
先に将棋のボードの形から考えます。
将棋のボードは9マス×9マスのグリッドです。マスの中に駒が一個ずつ並びます。
そして上から3行と下から3行は敵陣と自分の陣になります。
行単位で気軽に管理できるタグと言えば、「table」が考えられます。
行を表す「tr」タグにクラス名を付けると、敵と味方の陣を判別することが出来ます。
リストの「ul」タグを使うのも1つですが、ボードを組み出すため、連続81個の「li」タグを使わなければなりません。
後ほど、駒を動かしたり、反転したりするときに、その先のマスを計算することが困難になります。
そこで、「table」を使うことで計算が圧倒的にしやすくなります。
将棋ボードのマス目交点に四つの黒い点が付いています。
どのようにCSSを使って再現するのでしょうか。
私はまず黒い点に隣接するマスを探し出しました。
そして疑似要素「after」で小さい円を作り、positionで位置を指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
div .board tr:nth-child(3) td:nth-child(3)::after, div .board tr:nth-child(3) td:nth-child(6)::after, div .board tr:nth-child(6) td:nth-child(3)::after, div .board tr:nth-child(6) td:nth-child(6)::after { content: ''; position: absolute; right: -0.3rem; bottom: -0.3rem; width: 0.6rem; height: 0.6rem; background: #333; border-radius: 50%; } |
将棋のボードを作る際に、味方の陣と敵の陣が収まる「tr」タグに、
それぞれのクラス名を付けました。
しかし、それだけでは、敵と味方を完全に見分けることはできません。
自分の駒が相手の陣に入ると、自分の駒か、相手の駒か、判別しにくくなります。
見た目上は、三角の指し方向で一目で分かりますが、プログラミング上で判別しやすくするために、
駒にもクラスを付けるか「alt」属性を活用する必要があるのではないかと考え、今回はalt属性を使って駒の状態を把握することにしました。
ここでは、「飛車」を例にします。
「NhisyaA」
頭に付いている「N」は、成り駒であるかどうかを示します。
そして最後に付いている「A」を用いて、自分の駒か相手の駒かを判別します。
将棋では駒によって「動かし方」が違ってきます。
駒ごとに「動かし方」の関数を作成するのも1つの手です。
駒によっては動かし方に共通点があると気づきました。
概して言えば、上下左右と右上・左上・右下・左下になります。
その上、移動できるマス数も、何マスでも移動できるパターンと、一マスしか移動できないパターンに分れます。
パターンごとに、「動かし方」の関数を作って、その関数をそれぞれの駒に与えれば、コードの短縮に繋がるのではないかと閃きました。
(1)クリックした駒が今所在するマスの座標を取得します。
1 2 3 4 |
//駒の位置 row = $(game).closest('tr').index()+1; col = $(game).parent(); col = col.index()+1; |
(2)取得したマスの座標を元に移動先の座標を算出します。
1 2 3 4 5 6 7 8 9 |
//上 let up_check_one=()=>{ let gomaNow = $(`tr:nth-child(${row-1})>td:nth-child(${col})`); if(spaceCheck(user,gomaNow)=="1"){ $(gomaNow).addClass("option"); }else if(spaceCheck(user,gomaNow)=="2"){ $(gomaNow).addClass("option"); } } |
(3)それぞれの駒に、移動できる方向の関数を与えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//歩兵 先手・裏面 if(gomaName == "Nfuhe"){ up_check_one(); down_check_one(); left_check_one(); right_check_one(); upright_check_one(); upleft_check_one(); }//if //歩兵 先手・表面 if(gomaName == "fuhe"){ up_check_one(); }//if |
将棋では、駒を相手の陣に移動させると、成り駒へと変化させることができます。
ただし、成るかどうかは対局者の判断によります。
まず、親の「tr」タグに相手の陣を示すクラス名が付いているかどうかを「hasClass」で確認します。もしクラス名が付いていれば、「naru_flag」にtrueを与えます。
1 2 3 4 5 6 7 8 9 |
if(user=="userBGoma"){ if(_click_td.parents("tr").hasClass("userAArea")){ naru_flag=true; } }else{ if(_click_td.parents("tr").hasClass("userBArea")){ naru_flag=true; } } |
もし成ることが可能であれば、ポップアップウインドウで「なりますか?」と対局者に聞きます。
対局者が「ok」を押した場合、「switch」文を使って、各駒を成り駒に入れ替える処理を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
if(naru_flag){ let result = confirm('なりますか'); if(result){ switch(gomaName){ case "hisya": $(goma).attr('alt','Nhisya'); $(goma).attr('src','img/hisyaB.svg'); break; case "hisyaA": $(goma).attr('alt','NhisyaA'); $(goma).attr('src','img/hisyaB.svg'); break; ... } } } |
まず、指定する移動先のマスに駒が入っているかどうかを判断します。
もし駒が入っていれば、flagに「2」を与えます。
1 2 3 |
if(_click_td.children().hasClass("userBGoma")){ flag=2; } |
flagは2の場合、相手の駒を取得するプログラムを実行します。
1 2 3 4 5 6 7 8 9 10 11 12 |
//持ち駒の入れ箱 if(flag==2){ let use = $(".useArea li"); for(let i=0;i<use.length;i++){ if($(use[i]).hasClass($(event.target).children().attr('alt'))){ //取得した駒を自分の入れ箱に入れます $(use[i]).append($(event.target).children()); //動かしている駒を移動先のマスに入れます _click_td.append(goma); } } } |
最後に、もし移動先のマスにある駒が玉将であれば、勝負の処理に入ります。
1 2 3 |
if(attr('alt')=='owuA'){ //結果を表示します } |
以上、私が考えたJavaScriptで再現する将棋のアルゴリズムでした。
日常生活で生じる悩みを解決することと同じく、機能をどのように再現していくかは、
多数の方法があります。
自分なりの方法を掘り下げていくと、プログラミングが楽しくなります。
みなさんも是非プログラミングで将棋を作ってみてください。