var EHDI = EHDI || Object.create(null); EHDI.GAME = EHDI.GAME || Object.create(null); EHDI.GAME.components = EHDI.GAME.components || Object.create(null); EHDI.GAME.components.OpponentAI = function(playableCards, handCards, boardCards, enemyBoardCards, draftedCards) { this.playableCards = playableCards; this.handCards = handCards; this.boardCards = boardCards; this.enemyBoardCards = enemyBoardCards; this.draftedCards = draftedCards; this.effectCalculator = new EHDI.GAME.components.EffectCalculator(true); this.weightMap = []; this.lookAhead = 2; this.choices = null; } EHDI.GAME.components.OpponentAI.prototype.chooseFromHand = function(level) { var card; switch(level) { case 1: card = this.greedyAlgo(); break; case 2: card = this.smartAlgo(); break; default: card = this.randomCard(this.handCards); } return card; } EHDI.GAME.components.OpponentAI.prototype.pickCardsToLeave = function(level, nCards) { var cardTypes = EHDI.GAME.CardManager.CARD_TYPES; var nTypes = Object.keys(cardTypes).length; var arbitrariness; var type; var n = 0; var cardsToLeave = []; var sortedBoardCards = this.boardCards.slice(0); switch(level) { case 1: arbitrariness = 0.4; break; case 2: arbitrariness = 0.2; break; default: arbitrariness = 0.7; } sortedBoardCards.sort(function(a, b) { return a.type.weight - b.type.weight}); // console.log(sortedBoardCards); for(var i = sortedBoardCards.length-1; i >= 0; i--) { if(this.draftedCards.indexOf(sortedBoardCards[i]) < 0) { if((cardsToLeave.length < nCards && i <= nCards) || Math.random() >= arbitrariness) { // console.log("pick best card") cardsToLeave.push(sortedBoardCards[i]); n++; if(n >= nCards) break; } } } return cardsToLeave; } EHDI.GAME.components.OpponentAI.prototype.randomCard = function(cards) { return cards[EHDI.GAME.utils.randomInt(0, cards.length)]; } EHDI.GAME.components.OpponentAI.prototype.greedyAlgo = function() { this.weightMap = EHDI.GAME.utils.initArray(this.handCards.length, 0); var max = 0, maxIndex = 0; var mults = []; var points = []; for(var i = 0; i < this.boardCards.length; i++) { mults.push(this.boardCards[i].symbolMultiplier); points.push(this.boardCards[i].pointsGained); } for(var i = 0; i < this.handCards.length; i++) { if(!this.handCards[i].effect.isSpecial) { this.weightMap[i] = this.effectCalculator.calculate(this.handCards[i], this.boardCards, this.enemyBoardCards).pointsGained; } else { this.weightMap[i] = 0; } if(this.weightMap[i] > max) { maxIndex = i; max = this.weightMap[i]; } } for(var i = 0; i < this.boardCards.length; i++) { this.boardCards[i].symbolMultiplier = mults[i]; this.boardCards[i].pointsGained = points[i]; } if(max == 0) return this.randomCard(this.handCards); return this.handCards[maxIndex]; } EHDI.GAME.components.OpponentAI.prototype.smartAlgo = function() { this.choices = new EHDI.GAME.Tree(this.recentMove); var playerCards = this.deducePlayerCards(); this.iterations = 0; if(this.handCards.length > 1) { this.generateSearchTree(this.choices.root, this.boardCards.slice(0), this.handCards.slice(0), this.enemyBoardCards.slice(0), playerCards, 1); var move = EHDI.GAME.utils.minimax(this.choices.root, true); while(move.parent != this.choices.root) { move = move.parent; } return move.move; } else { return this.handCards[0]; } } EHDI.GAME.components.OpponentAI.prototype.generateSearchTree = function(parent, boardCards, handCards, enemyBoardCards, playerCards, turn) { var lookAhead = (this.handCards.length > this.lookAhead)? this.handCards.length-this.lookAhead:1; if(handCards.length <= lookAhead) { this.effectCalculator.resetState(); // console.log(boardCards.length + " : " + enemyBoardCards.length); var score = this.effectCalculator.groupCalculate(boardCards, enemyBoardCards); this.iterations++; var node = new EHDI.GAME.Node(handCards[lookAhead-1], score); return node; } else { if(turn == 1) { for(var i = 0; i < handCards.length; i++) { var node = new EHDI.GAME.Node(handCards[i]); var nextBoardCards = boardCards.concat([handCards[i]]); var nextHandCards = handCards.slice(); nextHandCards.splice(i, 1); turn = 0; parent.addChild(this.generateSearchTree(node, nextBoardCards, nextHandCards, enemyBoardCards, playerCards, turn)); } } else { for(var i = 0; i < playerCards.length; i++) { var node = new EHDI.GAME.Node(playerCards[i]); var nextBoardCards = enemyBoardCards.concat([playerCards[i]]); var nextHandCards = playerCards.slice(); nextHandCards.splice(i, 1); turn = 1; parent.addChild(this.generateSearchTree(node, boardCards, nextHandCards, nextBoardCards, handCards, turn)); } } return parent; } } EHDI.GAME.components.OpponentAI.prototype.getHighestWeightedCard = function() { return Math.max.apply(Math, this.weightMap); } EHDI.GAME.components.OpponentAI.prototype.deducePlayerCards = function(handCards, boardCards, enemyBoardCards) { var handCards = handCards || this.handCards; var boardCards = boardCards || this.boardCards; var enemyBoardCards = enemyBoardCards || this.enemyBoardCards; var playerCards = []; for(var i = 0; i < this.playableCards.length; i++) { if(handCards.indexOf(this.playableCards[i]) < 0 && boardCards.indexOf(this.playableCards[i]) < 0 && enemyBoardCards.indexOf(this.playableCards[i]) < 0) { playerCards.push(this.playableCards[i]); } } return playerCards; } EHDI.GAME.components.OpponentAI.prototype.updateCardSets = function(cardSets) { this.playableCards = cardSets.playableCards || this.playableCards; this.handCards = cardSets.handCards || this.handCards; this.boardCards = cardSets.boardCards || this.boardCards; this.enemyBoardCards = cardSets.enemyBoardCards || this.enemyBoardCards; this.draftedCards = cardSets.draftedCards || this.draftedCards; }