// ステージ2撃墜処理(基地航空隊) private static void St2LandBaseBreak(LandBase landBase, Fleet enemy, LandBaseAirsList landBaseAirsList, int ti, CutInType cutInType) { // 迎撃艦を一覧を算出し、それぞれの撃墜量を出す var breakPer = enemy.BreakPer; var breakFixed = enemy.BreakFixed(cutInType); // 撃墜処理 for (int wi = 0; wi < landBase.Team[ti].Weapon.Count; ++wi) { if (!landBase.Team[ti].Weapon[wi].IsStage2X) { continue; } // 迎撃艦を選択する int selectKammusuIndex = RandInt(0, breakPer.Count - 1); // 割合撃墜 if (RandInt(0, 1) == 1) { int breakCount = (int)(breakPer[selectKammusuIndex] * landBaseAirsList[ti][wi]); landBaseAirsList[ti][wi] -= breakCount; } // 固定撃墜 if (RandInt(0, 1) == 1) { int breakCount = breakFixed[selectKammusuIndex]; breakCount += CutInAddBonus[(int)cutInType]; landBaseAirsList[ti][wi] = Math.Max(landBaseAirsList[ti][wi] - breakCount, 0); } } }
private static int NowAirValueX(LandBase landBase, LandBaseAirsList landBaseAirsList, int ti) { int airValue = 0; var weaponList = landBase.Team[ti].Weapon; for (int wi = 0; wi < landBase.Team[ti].Airs.Count; ++wi) { airValue += weaponList[wi].AirValueX(landBaseAirsList[ti][wi]); } return(airValue); }
// モンテカルロシミュレーションを行う public static string MonteCarlo(Fleet friend, Fleet enemy, LandBase landBase, int simulationSize) { if (landBase == null) { return(MonteCarloImpl(friend, enemy, simulationSize)); } else { return(MonteCarloImpl(friend, enemy, landBase, simulationSize)); } }
// ステージ1撃墜処理(基地航空隊) private static void St1LandBaseBreak(LandBase landBase, LandBaseAirsList landBaseAirsList, int ti, AirWarStatus airWarStatus) { for (int wi = 0; wi < landBase.Team[ti].Weapon.Count; ++wi) { if (!landBase.Team[ti].Weapon[wi].IsStage1X) { continue; } int breakCount = landBaseAirsList[ti][wi] * RandInt(St1FriendBreakMin[(int)airWarStatus], St1FriendBreakMax[(int)airWarStatus]) / 256; landBaseAirsList[ti][wi] -= breakCount; } }
/// <summary> /// 入力された文字列を大艦隊クラスに変換する /// </summary> /// <param name="inputAirBaseText">文字列</param> /// <returns>大艦隊クラス</returns> public static LandBase ToLandBase(string inputAirBaseText) { var landbase = new LandBase(); // bas形式と考えて読み込む using (var rs = new System.IO.StringReader(inputAirBaseText)) { while (rs.Peek() > -1) { try { string getLine = rs.ReadLine(); var column = getLine.Split(','); if (column.Count() < 13) { continue; } var landBaseTeam = new LandBaseTeam(); int attackCount = int.Parse(column[0]); attackCount = (attackCount >= 2 ? 2 : 1); // 装備(データベースから情報を拾う) for (int i = 0; i < 4; ++i) { int id2 = DataBase.WeaponId(column[1 + i * 3]); if (id2 >= 0) { var tempWeapon = new Weapon(); tempWeapon.Id = id2; tempWeapon.Improvement = int.Parse(column[2 + i * 3]); tempWeapon.Proficiency = int.Parse(column[3 + i * 3]); tempWeapon.Complete(); landBaseTeam.Weapon[i] = tempWeapon; if (tempWeapon.Type.Contains("偵察機")) { landBaseTeam.Airs[i] = 4; } } } landBaseTeam.Complete(); landbase.Team.Add(landBaseTeam); landbase.AttackCount.Add(attackCount); } catch { continue; } } } if (landbase.TeamCount <= 0) { throw new Exception(); } return(landbase); }
// 記録する private static void MemoLeaveList(LandBase landBase, LandBaseAirsList landBaseAirsList, LandBaseList landBaseList, LeaveLandBaseAirsList landBaseLeaveAirsList) { for (int ti = 0; ti < landBaseAirsList.Count; ++ti) { bool allBrokenFlg = true; bool hasPAPBWB = false; for (int wi = 0; wi < landBase.Team[ti].Weapon.Count; ++wi) { if (landBase.Team[ti].Weapon[wi].IsStage2X) { hasPAPBWB = true; if (landBaseAirsList[ti][wi] != 0) { allBrokenFlg = false; } } ++landBaseLeaveAirsList[ti][wi][landBaseAirsList[ti][wi]]; } if (allBrokenFlg && hasPAPBWB) { ++landBaseList[ti]; } } }
// 結果を出力する public static void ResultData(Fleet friendFleet, Fleet enemyFleet, LandBase landBase, int simulationSize, out List <string> nameList, out List <List <List <double> > > perList) { nameList = new List <string>(); perList = new List <List <List <double> > >(); for (int i = 0; i < friendLeaveAirsList.Count; ++i) { for (int j = 0; j < friendLeaveAirsList[i].Count; ++j) { var tempList1 = new List <List <double> >(); for (int k = 0; k < friendFleet.Unit[i].Kammusu[j].SlotCount; ++k) { if (friendLeaveAirsList[i][j][k].Count == 1) { continue; } if (!friendFleet.Unit[i].Kammusu[j].Weapon[k].IsStage1) { continue; } var tempList2 = new List <double>(); for (int m = 0; m < friendLeaveAirsList[i][j][k].Count; ++m) { tempList2.Add(100.0 * friendLeaveAirsList[i][j][k][m] / simulationSize); } tempList1.Add(tempList2); } if (tempList1.Count > 0) { nameList.Add($"{i + 1}-{j + 1} {friendFleet.Unit[i].Kammusu[j].Name}"); perList.Add(tempList1); } } } if (landBase != null) { for (int ti = 0; ti < landBase.TeamCount; ++ti) { nameList.Add($"基地-{ti + 1}"); var tempList1 = new List <List <double> >(); for (int wi = 0; wi < landBase.Team[ti].Weapon.Count; ++wi) { if (landBaseLeaveAirsList[ti][wi].Count == 1) { continue; } if (!landBase.Team[ti].Weapon[wi].IsStage1X) { continue; } var tempList2 = new List <double>(); for (int m = 0; m < landBaseLeaveAirsList[ti][wi].Count; ++m) { tempList2.Add(100.0 * landBaseLeaveAirsList[ti][wi][m] / simulationSize); } tempList1.Add(tempList2); } perList.Add(tempList1); } } for (int i = 0; i < enemyLeaveAirsList.Count; ++i) { for (int j = 0; j < enemyLeaveAirsList[i].Count; ++j) { var tempList1 = new List <List <double> >(); for (int k = 0; k < enemyFleet.Unit[i].Kammusu[j].SlotCount; ++k) { if (enemyLeaveAirsList[i][j][k].Count == 1) { continue; } if (!enemyFleet.Unit[i].Kammusu[j].Weapon[k].IsStage1) { continue; } var tempList2 = new List <double>(); for (int m = 0; m < enemyLeaveAirsList[i][j][k].Count; ++m) { tempList2.Add(100.0 * enemyLeaveAirsList[i][j][k][m] / simulationSize); } tempList1.Add(tempList2); } if (tempList1.Count > 0) { nameList.Add($"{i + 1}-{j + 1} {enemyFleet.Unit[i].Kammusu[j].Name}"); perList.Add(tempList1); } } } }
// モンテカルロシミュレーション(基地航空隊がある場合) public static string MonteCarloImpl(Fleet friend, Fleet enemy, LandBase landBase, int simulationSize) { string output = "【モンテカルロシミュレーション】\n"; output += $"反復回数:{simulationSize}回\n"; // 初期状態を記録する var firstFriendAirsList = friend.AirsList; var firstLandBaseAirsList = landBase.AirsList; var firstEnemyAirsList = enemy.AirsList; // 保存用バッファを用意する MakeLists(firstFriendAirsList, out friendKammusuList, out friendLeaveAirsList); MakeLists(firstLandBaseAirsList, out landBaseList, out landBaseLeaveAirsList); MakeLists(firstEnemyAirsList, out enemyKammusuList, out enemyLeaveAirsList); // 反復計算を行う var friendAirsList = DeepCopyHelper.DeepCopy(firstFriendAirsList); var landBaseAirsList = DeepCopyHelper.DeepCopy(firstLandBaseAirsList); var enemyAirsList = DeepCopyHelper.DeepCopy(firstEnemyAirsList); var AirWarStatusCount = new List <List <int> >(); for (int ti = 0; ti <= landBase.TeamCount; ++ti) { AirWarStatusCount.Add(new List <int> { 0, 0, 0, 0, 0 }); } int unitCount = UnitCount(enemy.Unit.Count, friend.Unit.Count); for (int i = 0; i < simulationSize; ++i) { // 状態を初期化する CopyAirsList(firstFriendAirsList, friendAirsList); CopyAirsList(firstLandBaseAirsList, landBaseAirsList); CopyAirsList(firstEnemyAirsList, enemyAirsList); // 基地航空隊 for (int ti = 0; ti < landBase.TeamCount; ++ti) { for (int ai = 0; ai < landBase.AttackCount[ti]; ++ai) { #region ステージ1:航空戦 // 制空値を計算する int landBaseAirValue = NowAirValueX(landBase, landBaseAirsList, ti); int enemyAirValue_ = NowAirValueX(enemy, enemy.Unit.Count, enemyAirsList); // 制空状態を判断する AirWarStatus airWarStatus_ = CalcAirWarStatus(landBaseAirValue, enemyAirValue_); // 割合撃墜を行う // 基地航空隊を集中運用した際、1回目に来た際撃墜された分は // 2回目発動前に自動回復する(ここでの資源消費はないが熟練度はハゲる) if (landBase.AttackCount[ti] == 1 || ai == 1) { ++AirWarStatusCount[ti][(int)airWarStatus_]; St1LandBaseBreak(landBase, landBaseAirsList, ti, airWarStatus_); } St1EnemyBreak(enemy, enemy.Unit.Count, enemyAirsList, airWarStatus_); #endregion if (landBase.AttackCount[ti] == 1 || ai == 1) { #region ステージ2:対空砲火 var enemyCutInType_ = GetCutInType(enemy); St2LandBaseBreak(landBase, enemy, landBaseAirsList, ti, enemyCutInType_); #endregion } } } // 艦隊戦 #region ステージ1:航空戦 // 制空値を計算する int friendAirValue = NowAirValue(friend, unitCount, friendAirsList); int enemyAirValue = NowAirValue(enemy, unitCount, enemyAirsList); // 制空状態を判断する AirWarStatus airWarStatus = CalcAirWarStatus(friendAirValue, enemyAirValue); ++AirWarStatusCount[landBase.TeamCount][(int)airWarStatus]; // 割合撃墜を行う St1FriendBreak(friend, unitCount, friendAirsList, airWarStatus); St1EnemyBreak(enemy, unitCount, enemyAirsList, airWarStatus); #endregion #region ステージ2:対空砲火 var friendCutInType = GetCutInType(friend); var enemyCutInType = GetCutInType(enemy); St2FriendBreak(friend, enemy, unitCount, friendAirsList, enemyCutInType); St2EnemyBreak(enemy, friend, unitCount, enemyAirsList, friendCutInType); #endregion // 残数を記録する MemoLeaveList(friend, friendAirsList, friendKammusuList, friendLeaveAirsList); MemoLeaveList(landBase, landBaseAirsList, landBaseList, landBaseLeaveAirsList); MemoLeaveList(enemy, enemyAirsList, enemyKammusuList, enemyLeaveAirsList); } // 結果を書き出す output += "【制空状態】\n"; for (int ti = 0; ti <= landBase.TeamCount; ++ti) { output += (ti == landBase.TeamCount ? "本隊" : $"基地-{ti + 1}"); for (int i = 0; i < (int)AirWarStatus.Size; ++i) { var i2 = (AirWarStatus)i; output += $" {i2.ToStr()}:{Math.Round(100.0 * AirWarStatusCount[ti][i] / simulationSize, 1)}%"; } output += "\n"; } output += "【棒立ち率 [スロット毎の全滅率]】\n"; output += "自艦隊:\n"; for (int i = 0; i < friendKammusuList.Count; ++i) { for (int j = 0; j < friendKammusuList[i].Count; ++j) { int sum = firstFriendAirsList[i][j].Sum(); if (sum > 0) { output += $"{friend.Unit[i].Kammusu[j].Name}→{Math.Round(100.0 * friendKammusuList[i][j] / simulationSize, 1)}%"; for (int k = 0; k < friend.Unit[i].Kammusu[j].SlotCount; ++k) { if (firstFriendAirsList[i][j][k] > 0) { output += $" {k+1}:[{Math.Round(100.0 * friendLeaveAirsList[i][j][k][0]/ simulationSize, 1)}%]"; } } output += "\n"; } } } output += "基地航空隊:\n"; for (int ti = 0; ti < landBase.TeamCount; ++ti) { output += $"基地-{ti + 1}→{Math.Round(100.0 * landBaseList[ti] / simulationSize, 1)}%"; for (int wi = 0; wi < landBase.Team[ti].Weapon.Count; ++wi) { if (firstLandBaseAirsList[ti][wi] > 0) { output += $" {wi + 1}:[{Math.Round(100.0 * landBaseLeaveAirsList[ti][wi][0] / simulationSize, 1)}%]"; } } output += "\n"; } output += "敵艦隊:\n"; for (int i = 0; i < enemyKammusuList.Count; ++i) { for (int j = 0; j < enemyKammusuList[i].Count; ++j) { int sum = firstEnemyAirsList[i][j].Sum(); if (sum > 0) { output += $"{enemy.Unit[i].Kammusu[j].Name}→{Math.Round(100.0 * enemyKammusuList[i][j] / simulationSize, 1)}%"; for (int k = 0; k < enemy.Unit[i].Kammusu[j].SlotCount; ++k) { if (firstEnemyAirsList[i][j][k] > 0) { output += $" {k + 1}:[{Math.Round(100.0 * enemyLeaveAirsList[i][j][k][0] / simulationSize, 1)}%]"; } } output += "\n"; } } } return(output); }