デスクトップゲームデザインのバランス:Google AppScriptとGephiを使用したグラフの作成





みなさん、こんにちは!私の名前はニキータです。私のゴーストレターボードゲーム(今月Economicsからリリースされる予定)の開発の実際的な側面のいくつかを皆さんと共有したいと思います。私たちは開発プロセスにできるだけ体系的にアプローチしようとしたので、私たちの経験は誰かにとって興味深いかもしれません。





Ghost Lettersは、推論、ブラフ、連想的思考のための秘密の役割を持つ探偵ボードゲームです。「マフィア」や「イマジナリウム」をプレイしたいなら、きっとあなたもきっと気に入るはずです。ジャンルの現代のボードゲームから、それは「ミステリウム」と「クリミナリスト」に最も近いです。





割り当てられたタスク

Ghost Lettersの基本的な仕組みは、カードとさまざまなオブジェクトの画像(エビデンスカード)との関連付けに基づいています。そして、開発の初期段階の1つで、「アソシエーションのゲームでバランスを計算して構築することは可能ですか?」という質問をしました。実は、やってみませんか。





アソシエーションのバランスをとるタスクは、おおまかに次のとおりです。





  • 強力な「明確な」関連付けの数を最小限に抑えます。各カードは、理想的には、ほぼ同じ強さで他のいくつかのカードと関連付ける必要があります。





  • “ ”. , .





  • .





, , . 150 , – . , .





Google Docs

- Google , . - :





  • Google App Script. JS , -.





  • , . , .





  • , . - . .





Gephi

. .





:





. Google Sheets, , .





4 :





0 –

1 – ,

2 –

3 –





, – , .





, 150 150 ( , “”). , . , , , .





, , – , . , .





:





. id , . , id.





//     
function RefreshPictures() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  //  
  var sheet_a = ss.getSheetByName("");
  var range_a = sheet_a.getDataRange();
  //   
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  //    
  var row = sheet_a.getActiveCell().getRow();
  var col = sheet_a.getActiveCell().getColumn();
  
  //  id 
  var id1 = range_a.getCell(row, 1).getDisplayValue().toString();
  var id2 = range_a.getCell(1, col).getDisplayValue().toString();
  
  //        id
  var pos_pic1 = RowOfId(id1, range_p);
  var pos_pic2 = RowOfId(id2, range_p);
  
  // ,       id
  if (pos_pic1 != -1) {
    //       ,
    //      
    var pic1_f = range_p.getCell(pos_pic1, 2).getFormula();
    range_a.getCell(2, 1).setFormula(pic1_f);
  }
  else
  {
    range_a.getCell(2, 1).setValue("X");
  }
  
  if (pos_pic2 != -1) {
    var pic2_f = range_p.getCell(pos_pic2, 2).getFormula();
    range_a.getCell(2, 2).setFormula(pic2_f);
  }
  else
  {
    range_a.getCell(2, 2).setValue("X");
  }
}

//        id
function RowOfId(id, rng) {  
  var height = rng.getHeight();
  var data = rng.getValues();
  
  for (var i = 1; i < height; i++) {    
    if (data[i][0].toString() == id) {
      return i + 1;
    }
  }
  
  return -1;
}
      
      



. 150 , Google Sheets ( ). -, Google App Script .





//        Google Drive
function LoadPicturesFromDrive() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  var art_folder = DriveApp.getRootFolder().getFoldersByName("  ").next()
  var files = art_folder.getFiles();
  
  //     
  var i = 1;
  while (files.hasNext()) {
    var file = files.next();
    
    var file_name = file.getName();
    //     id 
    var id = file_name.slice(0, file_name.indexOf("."));
    
    //  id  
    sheet_p.getRange(i + 1, 1).setValue(id);
    
    //     
    file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
    var file_id = file.getId();
    
    //        IMAGE
    sheet_p.getRange(i + 1, 2).setFormula("=IMAGE(\"" + "https://drive.google.com/uc?export=download&id=" + file_id + "\")");
    
    i = i + 1;
  }
}
      
      



, Google Sheets Google Drive, - 10% . , , , . API Dropbox, . Dropbox , , .





//        Dropbox
function LoadPicturesFromDropbox() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_p = ss.getSheetByName("");
  var range_p = sheet_p.getDataRange();
  
  //    POST-
  var data = {
    "path": "",
    "recursive": false,
    "include_media_info": false,
    "include_deleted": false,
    "include_has_explicit_shared_members": false,
    "include_mounted_folders": true,
    "include_non_downloadable_files": true
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/files/list_folder";
  var response = UrlFetchApp.fetch(url, options);
  var json = JSON.parse(response.getContentText());
  
  //    
  for (var i = 0; i < json.entries.length; i++) {
    var name = json.entries[i].name;
    //     
    CreateSharedLink(name);
    var sh_link = GetSharedLink(name);
    
    //     id 
    id = name.slice(0, name.indexOf("."))
  
    //        IMAGE
    sheet_p.getRange(i + 2, 1).setValue(id);
    sheet_p.getRange(i + 2, 2).setFormula("=IMAGE(\"" + sh_link+"\")");
  }
}

//      
function CreateSharedLink(name) {
  //    POST-
  var data = {
    "path": ("/" + name),
    "settings": {
        "requested_visibility": "public",
        "audience": "public",
        "access": "viewer"
    }
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings";
  var response = UrlFetchApp.fetch(url, options);
}

//     
function GetSharedLink(name) {
  //    POST-
  var data = {
    "path": ("/" + name)
  };
  var payload = JSON.stringify(data);
  
  var options = {
    "method" : "POST",
    "contentType" : "application/json",
    "headers" : {
       "Authorization" : "Bearer [ ]"
    },
    "payload" : payload,
    muteHttpExceptions : true
  };
  
  //  POST-      
  var url = "https://api.dropboxapi.com/2/sharing/list_shared_links";
  var response = UrlFetchApp.fetch(url, options);
  var json = JSON.parse(response.getContentText());
  
  //       
  var urlForDownload = json.links[0].url.slice(0, -1) + '1';
  
  return urlForDownload;
}
      
      



Gephi ( ) CSV. : (: id, label) (: source, target, weight).





//         
function CreateGraph() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet_a = ss.getSheetByName("");
  var range_a = sheet_a.getDataRange();
  var data = range_a.getValues();
  var height = range_a.getHeight();
  
  //   
  var sheet_lbl = ss.getSheetByName("Graph Labels");
  //    
  var sheet_edg = ss.getSheetByName("Graph Edges");
  
  //     
  var weights = new Array("1", "2", "3");
  var edg_num = 0;
  
  //    
  var lbl_header = ["Id", "Label"];
  //     
  var edg_header = ["Source", "Target", "Weight"];
  
  //  
  sheet_lbl.clear();
  sheet_edg.clear();
  
  //    
  sheet_lbl.appendRow(lbl_header);
  sheet_edg.appendRow(edg_header);
  
  // ,        
  var tmp_arr = [];
  var tmp_arr_len = 0;
  
  //     (  )
  for (var i = 2; i < height; i++) {
    var id1 = data[i][0];
    var name1 = data[i][1];
    
    //      
    var lbl_row = [id1, name1];
    sheet_lbl.appendRow(lbl_row);
    
    for (var j = i + 1; j < height; j++) {
      var wt = data[i][j].toString();
      
      if (weights.includes(wt)) {
        var id2 = data[0][j];
        edg_num += 1;
        
        var edg_row = [id1, id2, wt];
        
        tmp_arr.push(edg_row);
        tmp_arr_len += 1;
        
        //      100 ,     .
        //        ,   
        //     Google App Script
        if (tmp_arr_len >= 100) {
          sheet_edg.getRange(sheet_edg.getLastRow() + 1, 1, tmp_arr_len, 3).setValues(tmp_arr);
          tmp_arr = [];
          tmp_arr_len = 0;
        }
      }
    }
  }
  
  //        
  if (tmp_arr_len > 0) {
    sheet_edg.getRange(sheet_edg.getLastRow() + 1, 1, tmp_arr_len, 3).setValues(tmp_arr);
    tmp_arr = [];
    tmp_arr_len = 0;
  }
}
      
      



Gephi ( ). , , , . .





, , . , “1” , . “2” “3”. .





, , , - . “”, . “” “” Gephi. , 100 :





, , “” . , . “”. , .





もちろん、グラフの視覚化とその分析方法に関しては、まだやるべきことがありますが、このアプローチはすでにうまく示されています。ゲームの開発でもグラフを使用した場合、あなたの経験について知ることは非常に興味深いでしょう。






プロジェクトの開発をフォローすることに興味がある場合は、VKontakteInstagramのゲームグループに登録してくださいここに、開発ノートやプロットスニペットなどを投稿します。








All Articles