将棋盤ウェブアプリ製作(盤表示編)

とある映画撮影のお芝居中に使う将棋盤アプリを作ることになったので実際にどのように書いたのか紹介します。要件としては、必ずしも初期配列では無い表示からKIF形式の進行データを使って遠隔青歯キーボードのリターンキーで一手づつ進めて行くと言うもの(一部マウス操作も有り)で、将棋にはバックギャモンやチェスのような駒の配置を効率的に表す標準的なID仕様が存在しないため、モデルの作り方から考える必要があります。盤表示、駒台表示、そして駒を動かせる場所のヒントの出し方、の三回に分けて、これから将棋アプリを作ろうとする方の参考になれば幸いです。

まずは BOARD CONFIG の各定数に対応した駒の画像を準備します。現存する将棋アプリは “ou” や “kaku” と言ったローマ字表記になってるのが気持ち悪くてチェスに習い英単語表記にしました。接頭辞の “b” は黒相手側、”w” は白自分側、接尾辞の “p” は「成る」を表す “Promoted” になります。 (後で知ったのですが将棋はチェスと異なり自分側が黒になるそうです)
参考: 将棋の「駒が成る」にも英語があった!?飛車→竜は? | 気になる英単語

// BOARD CONFIG
const PIECES = {'玉': 'K', '王': 'K', '飛': 'R', '角': 'B', '金': 'G', '銀': 'S', '桂': 'N', '香': 'L', '歩': 'P', '成': 'p', '龍': 'Rp', '馬': 'Bp', 'と': 'Pp'}
const BOARD_COLS = '987654321'.split('')
const BOARD_ROWS = '一二三四五六七八九'.split('')
const DEFAULT_POSITION = {
  '9一': 'bL',
  '8一': 'bN',
  '7一': 'bS',
  '6一': 'bG',
  '5一': 'bK',
  '4一': 'bG',
  '3一': 'bS',
  '2一': 'bN',
  '1一': 'bL',
  
  '8二': 'bR',
  '2二': 'bB',
  
  '9三': 'bP',
  '8三': 'bP',
  '7三': 'bP',
  '6三': 'bP',
  '5三': 'bP',
  '4三': 'bP',
  '3三': 'bP',
  '2三': 'bP',
  '1三': 'bP',
  '9七': 'wP',
  '8七': 'wP',
  '7七': 'wP',
  '6七': 'wP',
  '5七': 'wP',
  '4七': 'wP',
  '3七': 'wP',
  '2七': 'wP',
  '1七': 'wP',
  '8八': 'wB',
  '2八': 'wR',
  '9九': 'wL',
  '8九': 'wN',
  '7九': 'wS',
  '6九': 'wG',
  '5九': 'wK',
  '4九': 'wG',
  '3九': 'wS',
  '2九': 'wN',
  '1九': 'wL'}
// BOARD SETTINGS
const BOARD_WIDTH = 800

KIF形式を読み取る都合上、キーの値に使われる文字列を当てたオブジェクトを用意します。BOARD_COLSBOARD_ROWSは盤の上と右側に表示される位置情報です。ここではDEFAULT_POSITIONを初期位置としています。最後に装飾用の設定値として画面サイズに応じた盤の横幅をピクセル単位で用意しておきます。(もちろん決め打ちのサイズであれば別CSS記述にしても可で、状況に応じて高さの指定でも良しかと思います)

<ul id="shogiBoard"></ul>

更にHTMLファイルにはリストタグを用意しておき、JavaScriptで一列ずつFLEX表示のLIタグを生成しつつDIVを横並びに、それぞれIDと横幅、駒画像を使った背景のスタイル属性を付与しつつ配置していきます。参考までHEIGHT指定を省いているのは親要素がFLEXだったため高さが100%に伸縮されるからで、正確に正方形を維持するには属性を加えた方が望ましいと思います。

// BOARD DRAWING
const buildBoard = ()=>{
  const ulNode = document.getElementById('shogiBoard')
  ulNode.style.width = BOARD_WIDTH + 'px'
  for (let i = 0, maxRows = BOARD_ROWS.length; i < maxRows; i++) {
    const liNode = document.createElement('li')
    for (let j = 0, maxCols = BOARD_COLS.length; j < maxCols; j++) {
      const divNode = document.createElement('div')
      const id = BOARD_COLS[j] + BOARD_ROWS[i]
      divNode.id = id
      divNode.style.width = divNode.style.height = BOARD_WIDTH / maxCols + 'px'
      if(DEFAULT_POSITION[id] !== undefined){
        divNode.style.backgroundImage = 'url(pieces/' + DEFAULT_POSITION[id] + '.png)'
      }
      liNode.appendChild(divNode)
    }
    ulNode.appendChild(liNode)
  }
//ここから駒台の処理
}

ここで一つ技術的な勘違いをしていたのは、IDのマルチバイト使用についてで、このお陰で設計が楽になりました。
参考: 連想配列のキー名にマルチバイト文字は使えないと思い込んでいた話 – プログラミングを勉強するブログ

次回は初期表示が試合途中で取られた駒がある場合の駒台の表現について書きたいと思います。

参考:

投稿者: hkitago

個人事業主でウェブと iOS, Android アプリの開発者で一児の父親。JavaScript, ActionScript, AppleScript, PHP, SQL, ObjC, Swift, Java の読書実行試験運用管理を生業とし(Golang学習中)、Bind, Postfix, Apache を MacOS で使い、エディタは Vim, mi, Kod, Smultron, TextWrangler を経て Coda, Xcode, Android Studio, Atom といった IDE と CotEditor を重用しています。座右の銘は「アウトプットは量多い方がいい。フィルタは各自がやればいい。」です。