å°ãåãŸã§ããããã¢ã¯ã·ã§ã³ãéžæããåé¡ã解決ããããã«ãã¥ãŒã©ã«ãããã¯ãŒã¯ã䜿çšããç§ã®çµéšãå ±æããŸããã åé¡ã®æ¬è³ªã«ã€ããŠè©³ããã¯ãèšäºã®æåã®éšåãã芧ãã ããã
ãããŠã次ã®äœæ¥æ®µéã«ã€ããŠã話ãããŸãïŒ
決å®æš
ãã¥ãŒã©ã«ãããã¯ãŒã¯ã§ã®å€±æããïŒãããéåžžã«æçšãªïŒçµéšã®åŸã決å®æšãšã²ãŒã çè«ã®ç 究ãå§ããŸããã ãã®åé¡ãç 究ããéçšã§ãç§ã¯å€ãã®ã¢ã€ãã¢ãšæŠå¿µãæã¡ãŸãããã次ã®ããšã«æ±ºããŸããã
- ãããã«ã¯ãããªãŒã®æåã®ã¬ãã«ã§ããç¥ãããã¢ã¯ã·ã§ã³ïŒããŒãïŒã®ã»ããããããŸãã ãããã¯ãããããçŸåšã®ã²ãŒã ç¶æ³ã«æé©ãªãã®ãéžæããã¢ã¯ã·ã§ã³ã§ãã
- ãããã¯åã¢ã¯ã·ã§ã³ã®ãã·ãã¥ã¬ãŒã·ã§ã³ããè¡ããŸãã ãå¿ã®äžã§ããããããããšããŠããŸãã ãã®ã¢ã¯ã·ã§ã³ã®çµæã¯ãã²ãŒã ã®ç¶æ³ã®å€åãã€ãŸãç°å¢ã®å¥ã®ç¶æ ãžã®ç§»è¡ã«ãªããŸãã
- æ°ããç¶æ ã¯ãç¶æ³ãè©äŸ¡ããæ©èœã«è»¢éããããã®çµæã¯ç¹å®ã®å€ãã€ãŸãã¢ã¯ã·ã§ã³ã®ã¹ã³ã¢ã«ãªããŸãã
- ã¹ã³ã¢ãèšç®ããåŸããããã¯æ°ããä»®æ³ç¶æ³ãããã§ã«å®è¡ã§ããã¢ã¯ã·ã§ã³ã®ãªã¹ããçæããŸãã 次ã«ããããã移åãå®äºãã以å€ã®ããšãã§ããããã«ãªããŸã§ãã¹ããã2ãš3ãååž°çã«ç¹°ãè¿ããŸãã
- åãããªãŒã¬ãã«ã®ãã¹ãŠã®ã¢ã¯ã·ã§ã³ã®ãã€ã³ããèšç®ããããšãæ倧ã¹ã³ã¢ã¯ããªãŒã®èŠªã¬ãã«ã«æ»ããã¢ã¯ã·ã§ã³ã®åãªã¹ããçæããã¢ã¯ã·ã§ã³ã®ã¹ã³ã¢å€ã«å ç®ãããŸãã ãããã£ãŠã ã¹ã³ã¢å€ã¯ãããªãŒã®æ¥µç«¯ãªæããæ ¹ãŸã§ããããã¢ãããããããã«èŠããŸãã
- ããªãŒã®ééãå®äºãããšããã®æç¹ã§ããããå®è¡ã§ããåã¢ã¯ã·ã§ã³ã«ã¹ã³ã¢ãä»ããããŸãã ããã§ãæ倧ã¹ã³ã¢ã®ã¢ã¯ã·ã§ã³ãéžæããŠé©çšããã ãã§ãã
以äžã¯ããã®ã¢ã«ãŽãªãºã ã説æããååž°é¢æ°ã§ãã
ããããã®ã³ãŒã
function buildActionBranch (situation) { var actionList = createActionList(situation); /* createActionList , . actionList (newSituation). */ for(var i = 0; i < actionList.length; i++){ if(actionList[i].type !== "endTurn") { /* , */ actionList[i].branch = buildActionBranch(actionList[i].newSituation); /* selfScore - , score , */ actionList[i].score = actionList[i].selfScore + actionList[i].branch[0].score; /* actionList[i].branch[0] - score */ } else { actionList[i].score = actionList[i].selfScore; } } /* score */ actionList.sort(function (a, b) { if (a.score <= b.score) { return 1; } else if (a.score > b.score) { return -1; } }); /* actionList branch , */ return actionList; }
ããã¯ãååž°é¢æ°ã®æŠç¥å³ã«ãããŸãããå®éãããªãŒã®æ§ç¯ã«ã¯åŸ®åŠãªéãããããŸããããã«ã€ããŠã¯åŸã§èª¬æããŸãã ãŸãã決å®æšã«é¢ããããŒã¿ããã¡ã€ã«ã«æžã蟌ãããã®é¢æ°ãå®è£ ããŸãããããã«ãããåŸã§ã©ã®ããã«èŠããããæ確ã«ç¢ºèªã§ããŸãã

ãã·ãžã§ã³ããªãŒïŒJSONãã¡ã€ã«ãµã€ãºïŒ4kbïŒ
ãã®ããªãŒã¯ç§»åçšã«æ§ç¯ãããŠããããã£ã©ã¯ã¿ãŒã¯ãã§ã«å°ããšãã«ã®ãŒãæ¶è²»ããŠãããéžæã§ãããªãã·ã§ã³ã¯5ã€ã ãã§ãããå ãåœãŠããæ©èœã䜿çšããŠç§»åãå®äºãããšã3ã€ã®é£æ¥ã»ã«ã«ç§»åããŸãã åããŒãã§ãã¢ã¯ã·ã§ã³ã®ååã ã¹ã³ã¢ ïŒäžã®å³ïŒããã³selfScoreïŒäžã®å³ïŒã確èªã§ããŸãã ã«ãŒãã¬ãã«ã§ã¹ã³ã¢ãã©ã®ããã«åœ¢æãããããç°¡åã«è¿œè·¡ã§ããŸãã ãã¹ãŠã®é åãscoreã§ãœãŒããããŠãããšããäºå®ã«ãããæé©ãªãœãªã¥ãŒã·ã§ã³ã¯åžžã«äžçªäžã«ãããŸãã å¥ã®ããªãŒãæ€èšããŠãã ããã

æé©ãªãœãªã¥ãŒã·ã§ã³ãéããããªãŒïŒJSONãã¡ã€ã«ãµã€ãºïŒ169kbïŒ
æ®å¿µãªãããé«ãçŽ80,000ãã¯ã»ã«ãããããããã®å Žåã®å®å šãªããªãŒã衚瀺ããããšã¯ã§ããŸããã éãããã©ã³ããå³ããå·Šã«èŠãŠãããŸãããã
377ïŒã¿ãŒã³çµäºïŒ+ 378ïŒç§»åïŒ+ 373ïŒDefender Of The Faithãã£ã¹ãïŒ+ 312ïŒãã£ã¹ãPunishment DueïŒ+ 218ïŒç§»åïŒ= 1658
移åã¢ã¯ã·ã§ã³ã®å Žåã ã¹ã³ã¢å€ã¯1660ã§ãã衚瀺æã®æ°åã®æŽæ°å€ãžã®äžžãã«ãããå·®ã¯2ãã€ã³ãã§ãã ããªãŒã®æåã®ã¬ãã«ã®selfScoreå€ãèŠãŠã¿ãŸããããselfScoreã218ã®moveã¢ã¯ã·ã§ã³ã¯ãè¿é£ããŒãã®äžã§æ倧ã§ã¯ãããŸããã ãã®ã¬ãã«ã§ã®æåã®ã¢ã¯ã·ã§ã³ã¯ãDefender Of The FaithïŒ selfScore = 244ïŒã䜿çšããããšã§ãã ãã ãã 移åã¢ã¯ã·ã§ã³ã®åèšã¹ã³ã¢ïŒ1660察1652ïŒã¯äŸç¶ãšããŠå€§ãããªããŸãã ã³ãŒã¹å šäœã®ã¢ã¯ã·ã§ã³ãèããªããã°ããã®ç¶æ³ã§èœåã䜿çšããããšã¯ããã»ã©æé©ã§ã¯ãªãããšãããããŸãã
次ã«ããã®ã¢ã«ãŽãªãºã ã®ããŸããŸãªåŽé¢ã詳ããèŠãŠã¿ãŸãããã
ç¶æ³ã®è©äŸ¡
ç¶æ³ãè©äŸ¡ããã«ã¯ã次ã®æ©èœã䜿çšããŸãã
ããããã®ã³ãŒã
function situationCost (activeChar, myTeam, enemyTeam, wallPositions){ var score = 0; var effectScores = 0; // score += activeChar.curHealth / activeChar.maxHealth * 110; score += activeChar.curMana / activeChar.maxMana * 55; var positionWeights = arenaService.calculatePositionWeight(activeChar.position, activeChar, myTeam.characters, enemyTeam.characters, arenaService.getOptimalRange(activeChar), wallPositions); score += positionWeights[0] * 250 + Math.random(); score += positionWeights[1] * 125 + Math.random(); for(var j = 0; j < activeChar.buffs.length; j++){ if(activeChar.buffs[j].score) { effectScores = activeChar.buffs[j].score(activeChar, myTeam.characters, enemyTeam.characters, wallPositions); score += this.calculateEffectScore(effectScores, activeChar.buffs[j].name); } } for(j = 0; j < activeChar.debuffs.length; j++){ if(activeChar.debuffs[j].score) { effectScores = activeChar.debuffs[j].score(activeChar, myTeam.characters, enemyTeam.characters, wallPositions); score -= this.calculateEffectScore(effectScores, activeChar.debuffs[j].name); } } //myTeam - for(var i = 0; i < myTeam.characters.length; i++){ if(myTeam.characters[i].id !== activeChar.id) { var ally = myTeam.characters[i]; score += ally.curHealth / ally.maxHealth * 100; score += ally.curMana / ally.maxMana * 50; for(j = 0; j < ally.buffs.length; j++){ if(ally.buffs[j].score) { effectScores = ally.buffs[j].score(ally, myTeam.characters, enemyTeam.characters, wallPositions); score += this.calculateEffectScore(effectScores, ally.buffs[j].name); } } for(j = 0; j < ally.debuffs.length; j++){ if(ally.debuffs[j].score) { effectScores = ally.debuffs[j].score(ally, myTeam.characters, enemyTeam.characters, wallPositions); score -= this.calculateEffectScore(effectScores, ally.debuffs[j].name); } } } } //enemyTeam - for(i = 0; i < enemyTeam.characters.length; i++){ var enemy = enemyTeam.characters[i]; score -= Math.exp(enemy.curHealth / enemy.maxHealth * 3) * 15 - 200; score -= enemy.curMana / enemy.maxMana * 50; for(j = 0; j < enemy.buffs.length; j++){ if(enemy.buffs[j].score) { effectScores = enemy.buffs[j].score(enemy, enemyTeam.characters, myTeam.characters, wallPositions); score -= this.calculateEffectScore(effectScores, enemy.buffs[j].name); } } for(j = 0; j < enemy.debuffs.length; j++){ if(enemy.debuffs[j].score) { effectScores = enemy.debuffs[j].score(enemy, enemyTeam.characters, myTeam.characters, wallPositions); score += this.calculateEffectScore(effectScores, enemy.debuffs[j].name); } } } return score; }
ãã®ã¡ãœããã¯ãæŠéã«é¢äžãããã¹ãŠã®ãã£ã©ã¯ã¿ãŒãå®è¡ããããŸããŸãªãã©ã¡ãŒã¿ãŒã«å¯ŸããŠäžå®ã®ãã€ã³ããç²åŸããŸãã
- å¥åº· å³æ¹ã®ãã«ã¹çãé«ãã»ã©ããã€ã³ããå€ããªããŸãã ããã«ãäŸåé¢ä¿ã¯ç·åœ¢ã§ãã
score += activeChar.curHealth / activeChar.maxHealth * 110;
ãã ãã æµã®ãã£ã©ã¯ã¿ãŒã®å¥åº·ç¶æ ãè©äŸ¡ããå Žåããã€ã³ãã¯æ¬¡ã®åŒã䜿çšããŠä»äžãããŸãã
score -= Math.exp(enemy.curHealth / enemy.maxHealth * 3) * 15 - 200;
çŸåšã®å¥åº·ã®è»žã«æ²¿ã£ã0ãã1ã®ç¯å²ã®äžèšé¢æ°ã®ã°ã©ã
察æŠçžæãå®å šãªå¥åº·ç¶æ ã«ããå Žåãã»ãŒåãå€ãå³æ¹ã«è¿œå ãããåèšãã€ã³ãæ°ããå·®ãåŒãããŸãã ãã ããç¹å®ã®ãã£ã©ã¯ã¿ãŒã®å¥åº·ç¶æ ãäœãã»ã©ããã®ç¶æ³ã§åŸããããã€ã³ããå€ããªããŸãã å¥åº·ç¶æ ãæªããšããã€ã³ãã¯å·®ãåŒãããã«å ç®ãããŸãã ããã¯ãããããæµããŒã ãžã®ãã¡ãŒãžããã¹ãã¢ãªã³ã°ãããã®ã§ã¯ãªãã1ã€ã®ã¿ãŒã²ãããç Žå£ããããšã«åªåãéäžãããããã«è¡ãããŸãã - ããïŒèœåã䜿çšããããã®ãªãœãŒã¹ïŒã è€éãªæ©èœã¯ãã§ã«ååšãããå³æ¹ãšæµã®äž¡æ¹ã«ãšã£ãŠãã¹ãŠãç·åœ¢ã§ãã
- äœçœ®ã æŠå Žã§ã®ãã£ã©ã¯ã¿ãŒã®äœçœ®ã®è©äŸ¡ã«åæ Œããéã«ããã§ã«èšåããŸããã
ããã¯ãæ»æçãšé²åŸ¡çãª2ã€ã®éšåã§æ§æãããŠããŸãã æé©ãªæ»æäœçœ®ã¯ãèŠçå ã§æ»æã«æé©ãªè·é¢ã«ãã3人ã®æµãã£ã©ã¯ã¿ãŒã§ãã æè¯ã®é²åŸ¡é£å°ã¯ãèŠçå ã«ãããæ¯æŽèœåãé©çšããããã®æé©ãªè·é¢ã«ãã2人ã®å³æ¹ã§ãã ä»ã®ãã£ã©ã¯ã¿ãŒã®äœçœ®ãå€æŽããŠããã¢ã¯ãã£ããªãã£ã©ã¯ã¿ãŒã®å¯Ÿå¿ããã€ã³ãžã±ãŒã¿ãŒã®å€ã«åœ±é¿ãããããããžã·ã§ãã³ã°ã®ãã€ã³ãã¯ã¢ã¯ãã£ããªãã£ã©ã¯ã¿ãŒã«å¯ŸããŠã®ã¿ä»äžãããŸãã - ãšãã§ã¯ãã è©äŸ¡é¢æ°ã®æãé£ããéšåã ãããã決å®ããå¿
èŠããã
ãã£ã©ã¯ã¿ãŒã«1ã€ã®ãšãã§ã¯ããã©ã®çšåºŠéãªã£ãŠãããããä»ã®ãšãã§ã¯ããããéèŠã§ãã ãã®ãããåå¹æã«ã¯ã¹ã³ã¢é¢æ°ããããŸãã ããšãã°ãbuffïŒããïŒ
çŒizationã¯åŸã ã«ãã£ã©ã¯ã¿ãŒã®å¥åº·ãå埩ãããŸããããããçãããŸãã ãã®å¹æã®å Žåã ã¹ã³ã¢é¢æ°ã¯æ¬¡ã®ãšããã§ãã
ããããã®ã³ãŒãscore: function(owner, myTeam, enemyTeam, walls) { var buffer = {}; /* buffer - , */ for (var i = 0; i < myTeam.length; i++) { if (myTeam[i].id === this.casterId) buffer = myTeam[i]; } /* */ var heal = (this.variant * 80) * (1 + buffer.spellPower); /* , */ heal = arenaService.calculateExpectedHeal(heal, buffer); /* */ var positionWeights = arenaService.calculatePositionWeight(owner.position, owner, myTeam, enemyTeam, arenaService.getOptimalRange(owner), walls); return { effectScore: heal / 10, leftScore: this.left * 5, offensivePositionScore: 0, defensivePositionScore: - positionWeights[1] * 25, healthScore: - owner.curHealth / owner.maxHealth * 25, manaScore: owner.curMana / owner.maxMana * 15 }; }
ãããã£ãŠããšãã§ã¯ãã®ã¹ã³ã¢é¢æ°ã¯ã6ã€ã®ããããã£ãæã€ãªããžã§ã¯ããè¿ããŸãã
- effectScoreã å¹æèªäœã®æ°å€ã€ã³ãžã±ãŒã¿ã®ä¿®é£ŸåïŒäžãããããã¡ãŒãžã®å€§ãããåããæ²»çãç¹æ§ã®å¢å ãŸãã¯æžå°ãªã©ã
- leftScoreã ãšãã§ã¯ãã®ç¶ç¶æé修食åã
- offensivePositionScoreã æ»æäœçœ®ã®ä¿®é£Ÿåã
- defensivePositionScoreã å®åäœçœ®ã®ä¿®é£Ÿåã
- healthScoreã ãšãã§ã¯ãã®ææè ã®ãã«ã¹éã®ä¿®é£Ÿåã
- manaScoreã ãšãã§ã¯ãã®ææè ã®ããã®éã®ä¿®é£Ÿåã
ç¶æ³è©äŸ¡æ©èœã§ã¯ããããã®ãã¹ãŠã®ä¿®é£Ÿåãå ç®ãããŸãã ãã®éã¯ããã®å¹æã®ãå質ãã®ææšã«ãªããŸãã
ãçŒuterãã®å¹æã«é¢ããããããã¹ãŠã®ä¿®é£Ÿåã«ã€ããŠã次ã®çµè«ãå°ãåºãããšãã§ããŸãã
- å¥åº·ãå埩ããã°ããã»ã©ããã®éã¯å¢ããŸãã
- 圌ããã£ã©ã¯ã¿ãŒã«ãšã©ãŸãã»ã©ãéé¡ã¯é«ããªããŸãã
- 察æŠçžæã®å Žæã¯éé¡ã«åœ±é¿ããŸããã
- å³æ¹ããé ãããã»ã©ãéã¯å¢ããŸãã ãªããªã ä¿¡é Œã§ãã人ã¯ããªãã®ã§ãå®å šã«ãã¬ã€ããããšããå§ãããŸãã
- ãã£ã©ã¯ã¿ãŒã®ãã«ã¹ãå°ãªãã»ã©ãéãå€ããªããŸãã
- ãã£ã©ã¯ã¿ãŒãæ®ãããããå€ãã»ã©ãéãå€ããªããŸãã çµå±ã®ãšããããã®å¹æããããªãã§å®å šã«ç§ãã¡ãå»ãã®ã¯æãŸãããããŸããã
ã¢ã¯ã·ã§ã³ã·ãã¥ã¬ãŒã·ã§ã³
ãããã¢ã¯ã·ã§ã³ã®çµæãè©äŸ¡ããã«ã¯ïŒ
- ç°å¢ã®ç¶æ ãå®å šã«ã³ããŒããŠããã以éã®ãã¹ãŠã®ã¢ã¯ã·ã§ã³ãå ã®ç¶æ ã«å€åããªãããã«ããŸã
- ã¢ã¯ã·ã§ã³ïŒèœåã®ç§»åãŸãã¯äœ¿çšïŒã®ã·ãã¥ã¬ãŒã·ã§ã³ãå®è¡ããŸã
- è©äŸ¡é¢æ°ã䜿çšããŠç°å¢ã®æ°ããç¶æ ãè©äŸ¡ããŸã
ããšã§ã³ããŒã«æ»ããŸãããããã§ã¯ãã²ãŒã ã§æãåçŽãªã¡ã«ããºã ã®1ã€ã§ãããDie By The Swordãã®äŸã«åºã¥ããŠãã·ãã¥ã¬ãŒã·ã§ã³ãäœã§ãããã詳ããèŠãŠãããŸãã

ã²ãŒã å ã®åèœåã«ã¯ããã¡ãŒãžãäžããããå埩ããããå¹æãé©çšããããããã£ã¹ãæ©èœããããŸãã ãDie By The Swordãã®ãã£ã¹ãé¢æ°ãèŠãŠã¿ãŸãããã
ããããã®ã³ãŒã
cast : function (caster, target, myTeam, enemyTeam, walls) { /* */ caster.spendEnergy(this.energyCost()); caster.spendMana(this.manaCost()); /* , */ this.cd = this.cooldown(); /* */ if(caster.checkHit()){ /* */ var physDamage = randomService.randomInt(caster.minDamage * (1 + this.variant * 0.35), caster.maxDamage * (1 + this.variant * 0.35)); /* */ var critical = caster.checkCrit(); if(critical){ physDamage = caster.applyCrit(physDamage); } /* */ physDamage = target.applyResistance(physDamage, false); /* , */ caster.soundBuffer.push(this.name); /* physDamage */ target.takeDamage(physDamage, caster, {name: this.name, icon: this.icon(), role: this.role()}, true, true, critical, myTeam, enemyTeam); } else { /* , */ caster.afterMiss(target.charName, {name: this.name, icon: this.icon(), role: this.role()}, myTeam, enemyTeam); } /* , */ caster.afterCast(this.name, myTeam, enemyTeam); }
ãã®é¢æ°å ã«ã¯ãã©ã³ãã ãªæ§è³ªã®å°ãªããšã3ã€ã®æäœïŒæå·ã®å€å®ããããã®å€å®ãã¯ãªãã£ã«ã«ãããã®å€å®ïŒãããã³ã¯ã©ã€ã¢ã³ãã§åçãããµãŠã³ãã®è¿œå ãªã©ã®å®çšçãªæ¹æ³ãããããšãããããŸãã åœç¶ãçµæãäºæž¬ããããšã«ãªããšããã®é¢æ°ã䜿çšã§ããŸããã ãããã£ãŠã ãã£ã¹ãé¢æ°ã«å ããŠãåèœåã«ã¯castSimulationããããŸã ã
/* */ caster.spendEnergy(this.energyCost()); caster.spendMana(this.manaCost()); /* , */ this.cd = this.cooldown(); /* - */ var physDamage = (caster.minDamage * (1 + this.variant * 0.35) + caster.maxDamage * (1 + this.variant * 0.35)) / 2; /* */ physDamage = caster.hitChance * ((1 - caster.critChance) * physDamage + caster.critChance * (1.5 + caster.critChance) * physDamage); physDamage = target.applyResistance(physDamage, false); /* "" */ target.takeDamageSimulation(physDamage, caster, true, true, myTeam, enemyTeam); caster.afterCastSimulation(this.name);
åãæ¹æ³ãåãã®åäœãã·ãã¥ã¬ãŒãããããã«äœ¿çšãããŸã-åã«äžå¿ èŠãªãã®ãåãåããã©ã³ãã ãªæ¹æ³ãæ°åŠçæåŸ ã«çœ®ãæããŸãã
æé©å
åºæ¬çãªã¢ã«ãŽãªãºã ãæ§ç¯ãããåŸãç§ã¯æåã«ãããã移åãæ€èšããè¡åãèµ·ããããšãèŠãŸããã ç¹å®ã®ç¶æ³ã§äœããã¹ãããèªåãã¡ãã©ã®ããã«æ±ºå®ããããèŠãã®ã¯ãšãŠãã¯ãŒã«ã§ããã ãããããã®åŸã次ã®åé¡ãçªç¶æµ®äžããŸãã-æã 圌ãã¯ãã£ããé·ããšæã Node.jsããªãŒã®èšç®ãå¿ããããã«pingã€ãã³ããçºçããªãããã Socket.ioãã¯ã©ãã·ã¥ããŸãã æé©åãè¡ãæéã§ãã
1ïŒãããŒãªãªãŒã¹
ç§ãæåã«æãã€ããã®ã¯ãããªãŒã®æ§ç¯ãéåæã«ããããšã§ããã éåæã©ã€ãã©ãªãšeachOfã¡ãœããã䜿çšããŠãã¢ã¯ã·ã§ã³ãªã¹ããééãããã¹ãŠã®ãã¹ãéåæã«å€æãããã¹ãŠã®ã³ãŒã«ããã¯ã«æ»ããŸãã ããããããã¯æªåããã ãã§ã:(ããªãŒã¯ããé ããååã®æéã§æ§ç¯ãããæ·±ãããªãŒã®éåææ§ç¯ã®ãããã°ã¯å¥ã®æ¢æ±ã§ã...
ãã®åŸã process.nextTickã®å®éšãéå§ããããŸããŸãªã³ãŒããã©ããããããšããŸããããå¹æã«æ°ä»ããŸããã§ããã
ãã®çµæãç§ã¯æ¬¡ã®ã¹ããŒã ã«å°éããŸããïŒ
- ã¢ã¯ã·ã§ã³ã®æåã®ãªã¹ãã«ã€ããŠã¯ãéåæçã«ãã©ã³ãã®æ§ç¯ãéå§ããŸãã
- ãã¹ãŠã®ãã¹ãããããã©ã³ãã«ã€ããŠãããªãŒã®æ§ç¯ã¯åæçã§ãã
ããããã®ã³ãŒã
/* - " " */ function buildActionBranchAsync(myTeam, enemyTeam, activeCharId, wallPositions, cb){ var self = this; /* , */ var actionList = self.createActionList(myTeam, enemyTeam, activeCharId, wallPositions); async.eachOf(actionList, function(actionInList, index, cb){ /* */ process.nextTick(function() { if(actionInList.type != "endTurn" ) { /* */ actionInList.branch = self.buildActionBranchSync(actionInList.myTeamState, actionInList.enemyTeamState, actionInList.activeCharId, wallPositions); if(actionInList.branch && actionInList.branch[0]) { actionInList.score = actionInList.selfScore + actionInList.branch[0].score; } else { actionInList.score = actionInList.selfScore; } } else { actionInList.score = actionInList.selfScore; } cb(null, null); }); }, function(err, temp){ if(err){ return console.error(err); } actionList.sort(function (a, b) { if (a.score <= b.score) { return 1; } else if (a.score > b.score) { return -1; } }); cb(actionList); }) }
ãã®ãœãªã¥ãŒã·ã§ã³ã¯ãç§ãã¬ãã¥ãŒãããã®ã®äžã§æé«ã®ãã®ã§ããããšãå€æããŸããããäŸç¶ãšããŠãããã¯ãããŠããŸãã ãœã±ããã¯ç§»åã®é·ããçèãã§èœäžãç¶ããŸãã ããªãŒãæ§ç¯ãã process.nextTickã䜿çšããã¢ãŒããã¯ãã£ã®å€æŽã«é¢ããã¢ã€ãã¢ããæã¡ã®æ¹ãããã°ãåãã§ãæäŒãããŸãïŒ
2ïŒã¡ã¢ãªã解æŸãã
å¥ã®åé¡ã¯ãããããé·ãéèããŠããããã JavaScriptããŒãã®çš®é¡ã®ãšã©ãŒãã¡ã¢ãªäžè¶³ã«ãªãããšã§ããã ãã·ãžã§ã³ããªãŒãããã©ã«ãã®512 MBã®ã¡ã¢ãªã¹ããŒã¹ã«åãŸããªããããRAMã®ãªãŒããŒãããŒãããããšã¯æããã§ãã ãã¡ãããå²ãåœãŠãããã¹ããŒã¹ãæ¡åŒµããããšãã§ããŸãããããã¯ãŸã ééã£ãŠããŸããæå°éã«æããããã«ããŠãã ããã ç§ã®ã¢ãŒããã¯ãã£ã®åŒ±ç¹ã¯ãããªãŒãæ§ç¯ããããšãã®ãã¹ãŠã®æŠéç¶æ³ã®ç¶æ ãä¿åããªããã°ãªããªãã£ãããšã§ãã ãŸãããªããžã§ã¯ãã¯ã·ãã¥ã¬ãŒã·ã§ã³ã®åã«å®å šã«ã³ããŒããããããã¡ã¢ãªã¯åã«è©°ãŸã£ãŠããŸãã ç§ãæåã«ããããšã¯ãããªãŒãæ§ç¯ããåã«ãªããžã§ã¯ãã®ééãæžããããšã§ããã ãã®ãããããšãã°ãã·ãã¥ã¬ãŒã·ã§ã³ã«ãŸã£ããé¢ä¿ããªãCharacterãªããžã§ã¯ãã®ããããã£ãããã€ããããŸããã€ã³ãã³ããªããã°ãžã®ã¡ãã»ãŒãžã®é åãåçãããµãŠã³ãã®é åããã£ã©ã¯ã¿ãŒã®ãã¬ãŒã ã®è²ãªã©ã§ãã ããã§ãããªãŒãæ§ç¯ããåã«ããã£ã©ã¯ã¿ãŒãªããžã§ã¯ãã次ã®ããã«è§£æŸãããŸãã
ããããã®ã³ãŒã
function lightWeightTeamBeforeSimulation(team){ delete team.teamName; delete team.lead; for(var i = 0; i < team.characters.length; i++){ var char = team.characters[i]; delete char.battleTextBuffer; delete char.logBuffer; delete char.soundBuffer; delete char.battleColor; delete char.charName; delete char.gender; delete char.isBot; delete char.portrait; delete char.race; delete char.role; delete char.state; delete char.calcParamsByPoint; delete char.calcItem; delete char.updateMods; delete char.removeRandomBuff; delete char.removeRandomDebuff; delete char.removeAllDebuffs; delete char.removeRandomDOT; delete char.stealRandomBuff; delete char.afterDealingDamage; delete char.afterDamageTaken; delete char.afterMiss; delete char.removeImmobilization; delete char.afterCast; delete char.getSize; for(var j = 0; j < char.abilities.length; j++){ var ability = char.abilities[j]; delete ability.cast; delete ability.icon; delete ability.role; } for(j = 0; j < char.buffs.length; j++){ var effect = char.buffs[j]; delete effect.icon; delete effect.role; delete effect.apply; } for(j = 0; j < char.debuffs.length; j++){ var effect = char.debuffs[j]; delete effect.icon; delete effect.role; delete effect.apply; } } return team; }
ãããã£ãŠãåæåã®ãªããžã§ã¯ãã®ãµã€ãºã40ïŒ ä»¥äžåæžããããšãã§ããŸããã ããããããã§ãç§ãå®å šãªèšæ¶ããæããŸããã§ããã ãã®åé¡ã«ã€ããŠååãšè©±ãåã£ããšããããã©ã³ããã¡ã¢ãªã«ä¿åããŠãã¢ã¯ã·ã§ã³ã®ãªã¹ããè¿ãããåŸã¯æå³ããªãããšãããããŸããã çµå±ã®ãšãããç§ãã¡ã¯æãæåãããœãªã¥ãŒã·ã§ã³ã«ã®ã¿èå³ããããæ®ãã¯äžèŠã§ãã ããã§ãçµæãè¿ããçŽåŸã«ããã©ã³ããåé€ãããŸãïŒ
ããããã®ã³ãŒã
function buildActionBranchSync: function(myTeam, enemyTeam, activeCharId, wallPositions){ var actionList = this.createActionList(myTeam, enemyTeam, activeCharId, wallPositions); for(var z = 0; z < actionList.length; z++){ /* ... */ actionList[z].branch = this.buildActionBranchSync(actionList[z].myTeamState, actionList[z].enemyTeamState, actionList[z].activeCharId, wallPositions); actionList[z].score = actionList[z].selfScore + actionList[z].branch[0].score; delete actionList[z].branch; /* */ /* ... */ } /* sort actionList */ return actionList; }
ãã®åŸãã¡ã¢ãªãªãŒããŒãããŒãæ°žé ã«å¿ããŠããŸããã
3ïŒã¢ã¯ã·ã§ã³ã®ãªã¹ããççž®ãã
以åã®ãã¹ãŠã®æé©åã«ããããããã移åã«ã€ããŠèããããšã¯ãŸã çŽ30ç§ããããŸãã:(次ã®ã¹ãããã¯ãç¶æ³ã«å¿ããŠäœ¿çšã®èš±å®¹æ§ã説æããåèœåã«è¿œå ã®usageLogicé¢æ°ãè¿œå ããããšã§ãã ããã®æ©èœãå«ãã¢ã¯ã·ã§ã³ã®ãªã¹ããäœæããåã«ã次ã®ãã¹ããå®è¡ããŸãã
usageLogic: function(target) { /* 60% */ return target.curHealth < target.maxHealth * 0.6; }
ãããã£ãŠããããã¯ããã¹ããŒãã«ãªããéžæããã¢ã¯ã·ã§ã³ã®æ°ãå€§å¹ ã«åæžãããŸããã ããã«ãããããããå€æ°ã®ã¢ã¯ã·ã§ã³ãçæãã1ã€ã®èœåããããŸããã

ãã¹ããŒããªãã©ã€ããæ©èœã䜿çšãããšããã£ã©ã¯ã¿ãŒãåšå²6ã»ã«ã®ååŸå ã®äœçœ®ã«å ç±ã§ããŸãã
ææªã®å Žåããã®æ©èœã«ãã£ãŠ35ã®ã¢ã¯ã·ã§ã³ãçæãããããšãããããŸãã ããã§ã®æ±ºå®æšã¯éåžžã«åºãã§ãã ãœãªã¥ãŒã·ã§ã³ã¯ãèœåã®usageLogicé¢æ°ã®å®è£ ãçµããåŸãèªç¶ã«çãŸããŸããã å®éã移åã«å€±æãããã€ã³ããé€å€ããããšãã§ããŸãã äœçœ®ã®éã¿ãšcalculatePositionWeighté¢æ°ã«ã€ããŠã¯ãã§ã«è¿°ã¹ãŸããã ãããã£ãŠã移åå¯èœãªã»ã«ã®ãªã¹ããäœæãã段éã§ãããããã®åçæ§ãè©äŸ¡ããæã匱ãããžã·ã§ã³ãé€å€ã§ããŸãã
ããããã®ã³ãŒã
/* ... */ var bestMovePoints = []; /* , */ var movePoints = arenaService.findMovePoints(myTeam, enemyTeam, activeChar, false, wallPositions); /* */ for(var i = 0; i < movePoints.length; i++){ var weights = arenaService.calculatePositionWeight(movePoints[i], activeChar, myTeam.characters, enemyTeam.characters, arenaService.getOptimalRange(activeChar), wallPositions); /* (weights[0]) , (weights[1]) */ bestMovePoints.push({ point: movePoints[i], weightScore: weights[0] * 6 + weights[1] * 4 }) } /* */ bestMovePoints.sort(function (a, b) { if (a.weightScore <= b.weightScore) { return 1; } else if (a.weightScore > b.weightScore) { return -1; } }); /* 3 */ bestMovePoints = bestMovePoints.slice(0, 3); for(j = 0; j < bestMovePoints.length; j++){ /* */ }
ç§ã¯ãã®ã¢ãããŒãããéåžžã®åããšãã£ã©ã¯ã¿ãŒãåããèœåã®äž¡æ¹ã«é©çšããŸããïŒ ãå ã®é床ã ïŒã
4ïŒæèã®éŸå€
ãã®æé©åãè¡ã£ãŠãã審è°ãé ããå ŽåããããŸãã

ãåæ¢ããããªããèœåã¯ã850ãŠãããã®ãšãã«ã®ãŒãå埩ããŸãã
ãã®èœåã䜿çšããå¯èœæ§ã¯ãæèæéã2åãããã«ã¯3åã«å¢ãããŸãã äœããã®ã¢ã¯ã·ã§ã³ã®åŸããšãã«ã®ãŒãã»ãŒå®å šã«å埩ããã³ãŒã¹ãæ¹ããŠèããããšãã§ããŸãã
ãã®ãããªãé·ãã審è°ãé¿ããããã«ãããªãŒãæ§ç¯ããããã®ãããå€æéãå°å ¥ããŸããã çŸæç¹ã§ã¯3ç§ã§ãã ã¢ã¯ã·ã§ã³ã®ãªãã·ã§ã³ãæã€æ°ãããã©ã³ããæ§ç¯ããåã«ãä»åãã§ãã¯ããŸãããããè¶ ããå Žåãããã«ããªãŒãæ§ç¯ããããšã¯ã§ããããããã¯ãã§ã«ã«ãŠã³ããããã®ãèæ ®ããŠã¢ã¯ã·ã§ã³ãéžæããã ãã§ãããããã£ãŠãããŸããŸãªãã©ãããã©ãŒã ã§ã®ããã©ãŒãã³ã¹ã®åé¡ã解決ããŸãããããŒã«ã«ãã·ã³ã§ããªãŒãæ§ç¯ããé床ã¯1ç§ãããçŽ2000ã¢ã¯ã·ã§ã³ã§ãããç¡æãµãã¹ã¯ãªãã·ã§ã³ã®Herokuã¯ã©ãŠãã§ã¯1ç§ãããçŽ700ã¢ã¯ã·ã§ã³ã§ãããã©ãããã©ãŒã ãæäŸããã³ã³ãã¥ãŒãã£ã³ã°ãªãœãŒã¹ãå€ãã»ã©ããããã¯å²ãåœãŠããã3ç§ã§è§£æ±ºã§ããã¢ã¯ã·ã§ã³ãå¢ããŸããããããããšãã§ããªããŠãããããã¯ãŸã åããç¶ããããããã¬ã€ã€ãŒã«ãšã£ãŠã¯æ°ä»ãããã«æ®ãã§ãããã
ãããã«
ãã®ããã決å®æšã䜿çšããŠåé¡ã解決ããããšãã§ããŸããããã®ã¢ãããŒãã®é·æãšçæãç解ããŠã¿ãŸãããã
å©ç¹ïŒ
- ãããã®ãæèã®æµããå šäœã远跡ãããšã©ãŒãèŠã€ããããšãã§ããŸã
- åèœåãå¹æãç¶æ³è©äŸ¡ãã€ã³ãã埮調æŽããããšã§ãæŠéã®ãã©ã³ã¹ãå¶åŸ¡ã§ããŸã
- ãã¬ãŒãã³ã°ãµã³ãã«ã®ããŒã¿ãåéããããããŒã¿ããŒã¹ã«ãµã³ãã«ãä¿åãããããå¿ èŠã¯ãããŸããã
- ããŒã¿ããŒã¹ã«ãã¥ãŒã©ã«ãããã¯ãŒã¯ã¢ãã«ãä¿åããå¿ èŠã¯ãããŸãã
- AIããããã«é©å¿ãããå¿ èŠãªããæ°ããèœåãç°¡åã«è¿œå ã§ããŸãã
æ¬ ç¹ïŒ
- åã¢ã¯ã·ã§ã³ã«ã€ããŠãããªãŒããŒãããæ§ç¯ããå¿ èŠããããŸãããããã¯ãµãŒããŒãªãœãŒã¹ã«ãšã£ãŠéåžžã«é«äŸ¡ã§ã
- ãããã¯èšç·ŽãããŠããŸããã圌ãã¯åãééããäœåºŠãç¹°ãè¿ããŸãã
- å éšã®ææ決å®ã¢ã«ãŽãªãºã ããããã°ããã³æ§æããå¿ èŠããããŸã
ãã¡ãããåŠç¿äžè¶³ã¯ç§ãéåžžã«æãããŸãããã ãããã¥ãŒã©ã«ãããã¯ãŒã¯ãšçµã¿åãããŠãã·ãžã§ã³ããªãŒã䜿çšããŠAIãæ¹åããã¢ã€ãã¢ããããŸããçŸæç¹ã§ã¯ãç¶æ³ãè©äŸ¡ããæ©èœã«ã¯ãã²ãŒã ç¶æ³ã®ç¹å®ã®ããããã£ã®ãã€ã³ãæ°ã決å®ããäžå®ã®å€ããããŸããããšãã°ããã¬ãŒã€ãŒã®ãã«ã¹ãŠãããæ°ã®ã¹ã³ã¢ãã€ã³ãïŒ
score += activeChar.curHealth / activeChar.maxHealth * 110;
ççŽã«èšã£ãŠã110ãšããæ°åã¯å€©äºããæ¥ããã®ã§ãä»ã®å®æ°ãšã»ãŒãã©ã³ã¹ãåããŠããŸããããããå€æŽããŠãããã®åäœãã©ã®ããã«å€åãããã確èªããããšã誰ãçŠããŠããŸãããææ決å®æ©èœãããã¹ãŠã®å®æ°ãåéãããšããã®ãã²ãã ããååŸããŸãããã®åŸãããŸããŸãªãã²ãã ãã§äžé£ã®å®éšãè¡ããã»ãšãã©ã®æŠéã§åå©ãããã®ãèŠã€ããããå®éã®ãã¬ã€ã€ãŒãšã®æŠéçµæã«åºã¥ããŠæé©ãªãã²ãã ãã®éžæãèªååããããšãã§ããŸããããããããã¯ãŸã£ããç°ãªã話ã«ãªããŸãã
ãããã®èšäºããã¹ã¿ãŒããŠããã ããããããšãããããŸããç§ã®çµéšãããããžã§ã¯ãã«äººå·¥ç¥èœãæã¡èŸŒã¿ããåå¿è ã®ã²ãŒã éçºè ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
PS . , . , .