/// <summary> /// Writes <see cref="AIResult"/> and <see cref="Bitboard"/> objects as new line to the csv file. /// </summary> /// <param name="aiResult">The AI result.</param> /// <param name="bitboard">The bitboard.</param> public void WriteLine(AIResult aiResult, Bitboard bitboard) { using (var csvLogger = OpenOrCreateFile(FileExtension)) { if (csvLogger.BaseStream.Length == 0) { WriteValues(csvLogger, _header); } var values = new List <string> { GetCurrentTime(), aiResult.PVNodes.ToString(), aiResult.Stats.TotalNodes.ToString(), aiResult.Stats.EndNodes.ToString(), aiResult.Stats.AlphaBetaCutoffs.ToString(), aiResult.Stats.TranspositionTableHits.ToString(), aiResult.Stats.BranchingFactor.ToString(), aiResult.NodesPerSecond.ToString(), aiResult.TimePerNode.ToString(), aiResult.Depth.ToString(), aiResult.Score.ToString(), aiResult.PreferredTime.ToString(AITimeFormat), aiResult.Time.ToString(AITimeFormat), bitboard.Occupancy[0].ToString(), bitboard.Occupancy[1].ToString(), bitboard.GamePhase.ToString() }; WriteValues(csvLogger, values); } }
private void AICallback(AIResult result) { if (result == null) { return; } Controls.Find(result.LabelName, false).First().Text = result.Content; }
/// <summary> /// 原地休息 /// </summary> /// <param name="sprite">Sprite.</param> public AIResult Rest(RoleInstance sprite) { AIResult rst = new AIResult { MoveX = sprite.Pos.X, MoveY = sprite.Pos.Y, IsRest = true }; return(rst); }
private IEnumerator OnMove() { while (!isDone && moveRound == GameManager.Instance.GetCurRound()) { yield return(0); } if (moveRound != GameManager.Instance.GetCurRound()) { moveThread.Abort(); EndMove(); yield break; } for (int i = 0; i < result.Count; ++i) { AIResult v = result[i]; if (timer.GameTurnStatus == GameTurnStatus.WaitingForDrop) { if (timer.waitingTime > intervalSecond * result.Count) { float maxRandSec = timer.waitingTime - intervalSecond * result.Count; float minRandSec = 1f; maxRandSec = maxRandSec > 5 ? 5 : maxRandSec; minRandSec = maxRandSec > minRandSec ? minRandSec : maxRandSec; float randSec = UnityEngine.Random.Range(minRandSec, maxRandSec); yield return(new WaitForSeconds(randSec)); } } else if (timer.GameTurnStatus == GameTurnStatus.DropingMore) { if (timer.selectTime > intervalSecond * (result.Count - i)) { yield return(new WaitForSeconds(intervalSecond)); } } if (moveRound != GameManager.Instance.GetCurRound()) { break; } boardManager.SelectPiece(v.x, v.y); if (isBeSkilled) { isBeSkilled = false; break; } } EndMove(); }
private void Update() { if (executionTree != null) { if (executionTree.MoveNext()) { lastResult = executionTree.Current; } else { result.TrySetResult(lastResult); Destroy(this); } } }
void TurnEnd() { CurrentTurn = (CurrentTurn + 1) % 2; CheckCellEnable(); if (CurrentTurn == 0) { // 4つ目引数は何手先までを読むか AIResult result = Recursive(OthelloCells, CurrentTurn, false, 7); if (result.cell == null) { // null の場合は、CPUの番はパス return; } PutCell(result.cell, false); } }
/// <summary> /// 靠近自己最近的敌人 /// </summary> /// <returns>The to nearest enemy.</returns> /// <param name="sprite">Sprite.</param> /// <param name="moverange">Moverange.</param> public AIResult MoveToNearestEnemy(RoleInstance sprite, List <BattleBlockVector> range) { var tmp = GetNearestEnemyBlock(sprite, range); if (tmp == null) { return(null); } AIResult rst = new AIResult { Zhaoshi = null, MoveX = tmp.X, MoveY = tmp.Y, IsRest = true //靠近对手 }; return(rst); }
public static AIResult FindBestMove(bool side, Board board, int depth) { DateTime inicio = DateTime.Now; AIResult result = new AIResult(); int bestValue = side ? -100000 : 100000; List <Move> bestMoves = new List <Move>(); int alpha = -100000; int beta = 100000; result.leaves = 0; board.side = side; for (int i = 0; i < board.Count(); i++) { List <Move> moves = board.GetAllMovements(i); for (int j = 0; j < moves.Count; j++) { Board newBoard = board.Clone(); newBoard.MovePiece(moves[j].piece, moves[j].position); int value = EvaluateNode(newBoard, 1, !side, ref result.leaves, alpha, beta) + newBoard.EvaluateBoard() / 10; if ((!side && value <= bestValue) || (side && value >= bestValue)) { if (bestValue != value) { bestMoves.Clear(); } bestValue = value; bestMoves.Add(moves[j]); } } } result.bestValue = bestValue; var random = new System.Random(DateTime.Now.Second + alpha + beta + result.leaves); result.move = bestMoves[random.Next() % bestMoves.Count]; board.Initialize(); result.time = DateTime.Now.Subtract(inicio); return(result); }
public override void OnEnterState() { BattleboxHelper.Instance.HideAllBlocks(); BattleStateMechine.Instance.BindBattleAction(null); m_currentRole = BattleStateMechine.Instance.CurrentRole; if (m_currentRole == null) { GameUtil.LogError("ai当前角色为空"); return; } AIManager.Instance.GetAIResult(BattleStateMechine.Instance.CurrentRole, (result) => { m_aiResult = result; BattleBlockVector MoveTo = new BattleBlockVector(result.MoveX, result.MoveY); BattleBlockVector SkillTo = new BattleBlockVector(result.AttackX, result.AttackY); BattleZhaoshiInstance Skill = result.Zhaoshi; Jyx2Item Item = result.Item; DoAIAction(MoveTo, SkillTo, Skill, Item); }); }
public void GetAIResultClassic(RoleInstance role, Action <AIResult> callback) { //初始化范围逻辑 //rangeLogic = new RangeLogic(BattleboxHelper.Instance.IsBlockExists, BattleModel.BlockHasRole); //获得角色移动能力 int moveAbility = role.GetMoveAbility(); //行动范围 var range = rangeLogic.GetMoveRange(role.Pos.X, role.Pos.Y, moveAbility); //可使用招式 var zhaoshis = role.GetZhaoshis(false); //TODO:攻击计算缓存 by Cherubinxxx //AttackResultCache cache = new AttackResultCache(currentSprite, Field); //AI算法:穷举每个点,使用招式,取最大收益 AIResult result = null; double maxscore = 0; foreach (var zhaoshi in zhaoshis) { if (zhaoshi.GetStatus() != BattleZhaoshiInstance.ZhaoshiStatus.OK) { continue; } GetMoveAndCastPos(role, zhaoshi, range); BattleBlockVector[] tmp = m_GetMoveAndCastPosResult; if (tmp != null && tmp.Length == 2 && tmp[0] != null) { BattleBlockVector movePos = tmp[0]; BattleBlockVector castPos = tmp[1]; double score = GetSkillCastResultScore(role, zhaoshi, movePos.X, movePos.Y, castPos.X, castPos.Y, true); // yield return 0; //分帧 //if (score <= 0 && rst.HitEnemyCount > 0) //{ // score = ToolsShared.GetRandom(0, 1); //} if (score > maxscore) { maxscore = score; result = new AIResult { AttackX = castPos.X, AttackY = castPos.Y, MoveX = movePos.X, MoveY = movePos.Y, Zhaoshi = zhaoshi, IsRest = false }; } } } //考虑吃药 if (role.Items.Count > 0 && (role.Hp < 0.2 * role.MaxHp || role.Mp < 0.2 * role.MaxMp || role.Tili < 0.2 * Jyx2Consts.MaxTili)) { List <Jyx2Item> items = GetAvailableItems(role, 3); //只使用药物 foreach (var item in items) { double score = 0; //尽量吃刚刚好的药 if (item.AddHp > 0) { score += Mathf.Min(item.AddHp, role.MaxHp - role.Hp) - item.AddHp / 10; } if (item.AddMp > 0) { score += Mathf.Min(item.AddMp, role.MaxMp - role.Mp) / 2 - item.AddMp / 10; } if (item.AddTili > 0) { score += Mathf.Min(item.AddTili, Jyx2Consts.MaxTili - role.Tili) - item.AddTili / 10; } if (score > 0) { score *= 1.5;//自保系数大 } if (score > maxscore) { maxscore = score; var tmp = GetFarestEnemyBlock(role, range); result = new AIResult { MoveX = tmp.X, MoveY = tmp.Y, IsRest = false, Item = item }; } } } List <Jyx2Item> anqis = GetAvailableItems(role, 4); //获取暗器 //使用暗器 if (anqis.Count > 0) { foreach (var anqi in anqis) { BattleZhaoshiInstance anqizhaoshi = new AnqiZhaoshiInstance(role.Anqi, anqi); if (anqizhaoshi.GetStatus() != BattleZhaoshiInstance.ZhaoshiStatus.OK) { continue; } GetMoveAndCastPos(role, anqizhaoshi, range); BattleBlockVector[] tmp = m_GetMoveAndCastPosResult; if (tmp != null && tmp.Length == 2 && tmp[0] != null) { BattleBlockVector movePos = tmp[0]; BattleBlockVector castPos = tmp[1]; double score = GetSkillCastResultScore(role, anqizhaoshi, movePos.X, movePos.Y, castPos.X, castPos.Y, true); if (score > maxscore) { maxscore = score; result = new AIResult { AttackX = castPos.X, AttackY = castPos.Y, MoveX = movePos.X, MoveY = movePos.Y, Zhaoshi = anqizhaoshi, IsRest = false }; } } } } //Debug.Log(Time.realtimeSinceStartup); if (result != null) { callback(result); return; } //否则靠近自己最近的敌人 result = MoveToNearestEnemy(role, range); if (result != null) { callback(result); return; } //否则原地休息 callback(Rest(role)); return; }
public override void OnLeaveState() { m_aiResult = null; m_currentRole = null; }
// 引数の組み合わせで、そのときのturnから見たときの点数が戻り値 AIResult Recursive(OthelloCell[,] aiField, int turn, bool prevPass, int depth) { List <OthelloCell> cells = GetEnableCells(aiField, turn); if (cells.Count == 0) { // 打てるところがない if (prevPass) { // 前回パスしていたら、連続パスなのでゲーム終了 (AIが思考上でゲームが終わったときの判定も含む) // 白と黒の数をカウントする int white = 0; int black = 0; for (int i = 0; i < BoardSize; i++) { for (int j = 0; j < BoardSize; j++) { if (aiField[i, j].OwnerID == 0) { white++; } else if (aiField[i, j].OwnerID == 1) { black++; } } } if ((turn == 0 && white > black) || (turn == 1 && white < black)) { return(new AIResult { point = 99999 }); // 勝ちなのでスコアとしてはでかい数を返す } return(new AIResult { point = -99999 }); // 負けなのでスコアとして小さい数を返す } else { // 前回パスしていなかったら 普通にパスする(ターンを変えて関数を呼ぶ) // 相手のターンでの点数が自分の逆なのでマイナスにする // 一旦AIResult型で受け取ってポイント部分をマイナスにして新しく返す AIResult result = Recursive(aiField, (turn + 1) % 2, true, depth); return(new AIResult { point = -result.point }); } } else { // 打てるところがあるので打っていく // 一番点数が高いものを選ぶ int maxPoint = int.MinValue; int maxIndex = 0; for (int index = 0; index < cells.Count; index++) { // 引数で与えられた盤面をコピーする for (int i = 0; i < BoardSize; i++) { for (int j = 0; j < BoardSize; j++) { currentField[i, j].OwnerID = aiField[i, j].OwnerID; } } // その選択でひっくり返えす CheckAndReverse(currentField, cells[index], turn, true); // 打った場所の点数 int point = points[(int)cells[index].Location.y, (int)cells[index].Location.x]; // 1手先、打つ処理に渡す depthを1引いているのがポイント // Recursiveの呼び出しでは相手の点数によって自分の点数が下がるので 引く // 例えば、今、黒なら ターンが変わって白が打つ → 戻り値は白が打ったときの点数→ 黒から見ると逆の点数になるので引いている if (depth > 0) { point -= Recursive(currentField, (turn + 1) % 2, false, depth - 1).point; } if (maxPoint < point) { // 点数の更新をする、その時、何番目を選んだかも保持する maxPoint = point; maxIndex = index; } } // 計算した点数と、そのときに選ぶセル返すようにする return(new AIResult { point = maxPoint, cell = cells[maxIndex] }); } }
public AILesson(int segIdx, AIInputBuffer inputBuffer, AIResult result) { _segIdx = segIdx; _inputBuffer = inputBuffer; Result = result; }