六帖のかたすみ

DVを受けていた男性。家を脱出して二周目の人生を生きています。自閉症スペクトラム(受動型)です。http://rokujo.org/ に引っ越しました。

詰碁印刷2

詰碁印刷のためのプログラム - diary 六帖
の続き。今日はSGFのパーサーを作るところまでで時間切れで終了。来週はcanvasに問題図と正解図を描いて並べて表示したい。
kickzone/SGFPrint · GitHub

SGFファイル仕様参考
SGFƒtƒ@ƒCƒ‹Œ`Ž®


次のサイトを参考にして、とてもスタイリッシュなswitch文の変形が書けました。ありがとうございます。qiita.com
コードの先頭で使ってます。

var SGFParser = (function(){

  var parseItemSub = {};
  //黒置き石
  parseItemSub['AB'] = function(str, item){
    item.okiishi.push(new SGFStone(BLACK, str));
  }
  //白置き石
  parseItemSub['AW'] = function(str, item){
    item.okiishi.push(new SGFStone(WHITE, str));
  }
  //コメント
  parseItemSub['C'] = function(str, item){
    item.comment = str;
  }
  //黒着手
  parseItemSub['B'] = function(str, item){
    item.stone = new SGFStone(BLACK, str);
  }
  //白着手
  parseItemSub['W'] = function(str, item){
    item.stone = new SGFStone(WHITE, str);
  }


  return {
    //SGFファイル全体のパース
    parse: function(content, element){
      //改行は邪魔なので全部取っ払う
      content = content.replace(/[\n\r]/g,"");

      var nodeStack = []; //スタック
      var prevNode = null;
      var startIdx = -1;
      //ノードに分割
      for(var i=0; i<content.length; i++){
        if(content[i] == "("){
          //ノード開始
          //いま見ているノードをpushして次のノードを作成
          if(startIdx != -1){
            var node = new SGFNode(content.slice(startIdx, i));
            if(nodeStack.length == 0){
              //ルートノードを設定
              element.root = node;
            } else {
              //最後のノードの子ノードとしてpush
              nodeStack[nodeStack.length-1].childNodes.push(node);
            }
            nodeStack.push(node);
          }
          //ノードの文字列開始
          startIdx = i + 1;
        }else if(content[i] == ")"){
          //ノード終了
          //いま見ているノードがあれば新規作成
          if(startIdx != -1){
            var node = new SGFNode(content.slice(startIdx, i));
            if(nodeStack.length == 0){
              //ルートノードを設定
              element.root = node;
            } else {
              //最後のノードの子ノードとしてpush
              nodeStack[nodeStack.length-1].childNodes.push(node);
            }
          } else {
            //見ているノードがない、すなわち終了カッコが連続した場合は、スタックを1つpop
            nodeStack.pop();
          }
          startIdx = -1;
        }
      }
    },

    //ノードのパース
    parseNode: function(text, node){
      //アイテムに分割
      var startIdx = -1;
      for(var i=0; i<text.length; i++){
        if(text[i] == ";"){
          if(startIdx != -1){
            var item = new SGFItem(text.slice(startIdx+1, i));
            node.items.push(item);
          }
          startIdx = i;
        }
      }
      if(startIdx != -1){
        var item = new SGFItem(text.slice(startIdx+1));
        node.items.push(item);
      }
    },

    //アイテムのパース
    parseItem: function(text, item){
      var id = "";
      var str = "";
      var startKakko = -1;
      var startId = -1;
      for(var i=0; i<text.length; i++){
        if(text[i] == "["){
          startKakko = i;
          if(startId != -1){
            id = text.slice(startId, i);
          }
          startId = -1;
        }else if(text[i] == "]"){
          str = text.slice(startKakko+1, i);
          startKakko = -1;
          //parseItemSubに処理があればそれを実行
          if(id in parseItemSub){
            parseItemSub[id](str, item);
          }
        }
        else{
          if(startKakko == -1 && startId == -1){
            startId = i;
          }
        }
      }
    }
  }
})();