public override Move move(IField field, int teamId, int turn) { Stopwatch sw = new Stopwatch(); sw.Start(); mMyTeamId = teamId; MaxMinBitField f = new MaxMinBitField(field, teamId, turn); MaxNode root = new MaxNode(f); Move bestMove = null; double bestScore = -1; int d = 1; Dictionary <ulong, MaxNode> maxNodesCache = new Dictionary <ulong, MaxNode>(100000); Dictionary <ulong, MinNode> minNodesCache = new Dictionary <ulong, MinNode>(100000); for (;; d++) { maxNodesCache.Clear(); minNodesCache.Clear(); double s = root.search(d, Double.NegativeInfinity, Double.PositiveInfinity, sw, maxNodesCache, minNodesCache); if (s < 0) { break; } bestMove = root.getBestChild().getLastMove(); bestScore = root.getScore(); if (s < 0.0001 || s >= 0.9999) { break; } } Debug.WriteLine("s:" + bestScore + "(d=" + d); mTotalDepth += d; return(bestMove); }
public MaxMinBitField(MaxMinBitField other) { mMyGoodGhostBit = other.mMyGoodGhostBit; mMyEvilGhostBit = other.mMyEvilGhostBit; mEnemyGhostBit = other.mEnemyGhostBit; mEnemyEvilNum = other.mEnemyEvilNum; mEnemyGoodNum = other.mEnemyGoodNum; mMyPlayerId = other.mMyPlayerId; mTurn = other.mTurn; mNextPlayerId = other.mNextPlayerId; }
static public double Score(MaxMinBitField f) { double myGhostTypeScore = f.countMyGood() * 0.8 + f.getEnemyEvil() * 0.2; double enemyGhostTypeScore = f.getEnemyGood() * 0.8 + f.getEnemyEvil() * 0.2; double myManhattanScore = f.myGoodManhattanScore() * 0.6 + f.myEvilManhattanScore() * 0.4; double enemyManhattanScore = f.enemyManhattanScoreAllColor(); double myScore = myGhostTypeScore * 1000 - myManhattanScore; double enemyScore = enemyGhostTypeScore * 1000 - enemyManhattanScore; double s = myScore / (myScore + enemyScore); // Debug.WriteLine(f + "Score:" + s); return(s); }
private static List <Move> sMovesBuff = new List <Move>(6 * 4); // 高速化のための魔改造的バッファ public static List <Move> CreateMoves(MaxMinBitField field, int teamId) { sMovesBuff.Clear(); ulong myEvilGhostBit = field.mMyEvilGhostBit; ulong myGoodGhostBit = field.mMyGoodGhostBit; ulong myGhostBit = myEvilGhostBit | myGoodGhostBit; ulong targetGhostBit = (teamId == field.mMyPlayerId) ? myGhostBit : field.mEnemyGhostBit; ulong unpassable = targetGhostBit | cWall; // ulong left = (targetGhostBit >> 1) & ~unpassable; ulong right = (targetGhostBit << 1) & ~unpassable; ulong up = (targetGhostBit >> 7) & ~unpassable; ulong down = (targetGhostBit << 7) & ~unpassable; //いずれかに遷移できたものを残す ulong movable = (left << 1) | (right >> 1) | (up << 7) | (down >> 7); while (targetGhostBit != 0) { var target = Bit.rightOneBits(targetGhostBit); int index = Bit.GetNumberOfTrailingZeros(target); int x = index % 7 - 1; int y = index / 7 - 1; foreach (Way w in WayUtil.way4) { var toBit = w == Way.Left ? (target >> 1) : w == Way.Right ? (target << 1) : w == Way.Up ? (target >> 7) : target << 7; if ((toBit & unpassable) != 0) { continue; } sMovesBuff.Add(new Move(new TPoint(x, y), w)); } targetGhostBit &= ~target; } return(sMovesBuff); }
public double search(int depth, double alpha, double beta, Stopwatch sw, Dictionary <ulong, MaxNode> maxNodsCache, Dictionary <ulong, MinNode> minNodesCache) { if (mField == null) { if (sw.ElapsedMilliseconds > 200) { return(-1.0); } mField = new MaxMinBitField(mParent.getField()); var result = mField.updateByMyMove(mLastMove); mValue = result[0]; mProb = result[1]; } if (depth >= 4) { ulong hash = mField.TransPositionHash(); MinNode node = null; if (minNodesCache.TryGetValue(hash, out node)) { mScore = node.getScore(); return(mScore); } else { minNodesCache.Add(hash, this); } } if (mProb == 1.0) { mScore = mValue; return(mValue); } if (depth <= 0) { mScore = mProb * mValue + (1.0 - mProb) * MaxMinVotingPlayer.Score(mField); return(mScore); } if (mChildList == null) { var moveList = MaxMinBitField.CreateMoves(mField, mField.getNextPlayerId()); mChildList = new List <MaxNode>(moveList.Count); foreach (Move m in moveList) { mChildList.Add(new MaxNode(m, this)); } } else { // 昇順 mChildList.Sort((MaxNode n0, MaxNode n1) => { return(n0.getScore() > n1.getScore() ? 1 : n0.getScore() < n1.getScore() ? -1 : 0); }); } mScore = Double.PositiveInfinity; foreach (MaxNode node in mChildList) { double s = mProb * mValue; if (s >= mScore) { continue; } double childValue = node.search(depth - 1, alpha, beta, sw, maxNodsCache, minNodesCache); if (childValue < 0) { //打ち切り return(childValue); } s += (1.0 - mProb) * childValue; if (s < mScore) { mScore = s; if (s < beta) { beta = s; if (s <= alpha) { break; } } } } return(mScore); }
public MaxNode(MaxMinBitField field) { mField = field; mLastMove = null; mParent = null; }