/// <summary> /// 削除できる可能性のあるスライムの分析する /// </summary> /// <param name="context">フィールド状態</param> /// <param name="player">プレイヤ</param> /// <param name="param">パラメータ</param> /// <returns>削除できる可能性のあるスライム数</returns> public int Analyze(FieldContext context, Player.Index player, Param param) { Debug.Assert(param.TargetSlime != Slime.None, "対象スライムがNoneはありえません"); var _context = context.DeepCopy(); // フィールドから削除対象のスライムを削除する foreach (var slime in param.ErasedSlimes) { if (slime == param.TargetSlime) { continue; } _context.SlimeFields[(int)player][slime] = Enumerable.Range(0, FieldContextConfig.FieldUnitCount).Select(i => 0u).ToArray(); } // 移動可能スライムも落下させたいので、情報のみ場外においやってしまう MovableSlime.ForEach(index => { var movable = _context.MovableSlimes[(int)player][(int)index]; movable.Index = 0; movable.Position = (int)index; }); // 重力ですべて落下させる this.Gravity.Update(_context, player, GravityParam); // スライムを消済にマーキングする this.ErasingMarker.Update(_context, player, ErasingMarkerParam); // 消済スライム数をカウントする return(SlimeCountHelper.GetSlimeCount(_context, player, Slime.Erased)); }
public int Analyze(FieldContext context, Player.Index player) { var min = 99; var max = -99; for (var column = FieldContextConfig.OneLineBitCount - FieldContextConfig.VerticalLineLength; column < FieldContextConfig.OneLineBitCount; column++) { var exists = false; for (var unit = FieldContextConfig.MaxHiddenUnitIndex + 1; unit < FieldContextConfig.FieldUnitCount; unit++) { for (var line = 0; line < FieldContextConfig.FieldUnitLineCount; line++) { exists = FieldContextHelper.ExistsSlime(context, player, unit, column + (line * FieldContextConfig.OneLineBitCount)); if (exists) { var top = (unit - FieldContextConfig.MaxHiddenUnitIndex + 1) * FieldContextConfig.FieldUnitLineCount + line; min = Math.Min(top, min); max = Math.Max(top, max); break; } } if (exists) { break; } } } min = min == 99 ? 0 : min; max = max == -99 ? 0 : max; return(max - min); }
/// <summary> /// 起こりうる最大連鎖回数を分析します /// </summary> /// <returns>起こりうる最大連鎖回数</returns> /// <param name="context">フィールド状態</param> /// <param name="player">プレイヤ</param> public int Analyze(FieldContext context, Player.Index player) { int maxChain = 0; // 移動可能パターンを取得 var movePatterns = CompleteReadingHelper.GetAllMovePatterns(); // 分析対象の移動可能スライムを生成 var usingSlimes = context.UsingSlimes; var slimePatterns = new List <Slime[]>(); slimePatterns.Add(new[] { usingSlimes[0], usingSlimes[1] }); slimePatterns.Add(new[] { usingSlimes[2], usingSlimes[3] }); // 自動移動機能を生成 var updater = DiProvider.GetContainer().GetInstance <AutoMoveAndDropUpdater>(); updater.Inject(context.UsingSlimes); // 各移動可能スライムの全パターンを試していく foreach (var slimePattern in slimePatterns) { var _context = context.DeepCopy(); // 移動可能スライムを書き換える for (var movable = 0; movable < MovableSlime.Length; movable++) { var org = _context.MovableSlimes[player.ToInt()][(int)movable]; var valid = (org.Index == FieldContextConfig.MaxHiddenUnitIndex && org.Position == FieldContextConfig.MovableSlimeInitialShiftAfterDroped + (FieldContextConfig.OneLineBitCount * (int)movable)); if (!valid) { return(0); } // 元の移動可能スライムを消す _context.SlimeFields[player.ToInt()][org.Slime][org.Index] &= ~(1u << org.Position); // 色を書き換える org.Slime = slimePattern[(int)movable]; } // 自動移動を実行 foreach (var movePattern in movePatterns) { var _movedContext = _context.DeepCopy(); var param = new AutoMoveAndDropUpdater.Param() { Pattern = movePattern, }; updater.Update(_movedContext, player, param); maxChain = Math.Max(maxChain, param.Chain); } } // 試行内の最大連鎖数を返却 return(maxChain); }
/// <summary> /// 2プレイヤ分のフィールド情報 + NEXTスライム情報の文字列から対象プレイヤのフィールド文字列のみを抽出します。 /// </summary> /// <param name="orgLines">2プレイヤ分のフィールド情報 + NEXTスライム情報の文字列</param> /// <param name="player">対象プレイヤ</param> /// <returns>対象プレイヤのフィールド文字列</returns> private static List <string> ExtractOnePlayerFieldLines(string[] orgLines, Player.Index player) { var targetIndex = player == Player.Index.First ? FieldIndex.FirstPlayer : FieldIndex.SecondPlayer; var lines = new List <string>(); foreach (var orgLine in orgLines) { // 対象プレイヤのフィールド情報を取得 var line = orgLine.Split(SimpleText.Separator.Player); lines.Add(line[(int)targetIndex]); } Debug.Assert(lines.Count() == SimpleText.Length.Field - 1, "フィールドの行数が不正です。行数:" + lines.Count()); return(lines); }
/// <summary> /// 自動移動を実行します。 /// </summary> /// <param name="context">フィールド状態</param> /// <param name="player">プレイヤ</param> /// <param name="param">パラメータ</param> public void Update(FieldContext context, Player.Index player, Param param) { Debug.Assert(this.HasInjected, "依存性の注入が完了していません"); if (!(context.FieldEvent[(int)context.OperationPlayer] == FieldEvent.None || context.FieldEvent[(int)context.OperationPlayer] == FieldEvent.End)) { return; } #if DEBUG for (var i = 0; i < context.UsingSlimes.Length; i++) { Debug.Assert(context.UsingSlimes[i] == this.UsingSlimes[i], "使用スライムが不正です"); } #endif // 回転と横移動 foreach (var p in param.Pattern) { context.OperationDirection = p; context = this.Game.Update(context); } // 最後まで落下させる while (!context.Ground[(int)player] && context.FieldEvent[(int)player] != FieldEvent.End) { context.OperationDirection = Direction.Down; context = this.Game.Update(context); } // 接地したら即設置完了にする context.BuiltRemainingTime[(int)player] = -1; context.OperationDirection = Direction.None; context = this.Game.Update(context); // イベント終了 or ゲーム終了まで更新する while (context.FieldEvent[(int)player] != FieldEvent.None && context.FieldEvent[(int)player] != FieldEvent.End) { context = this.Game.Update(context); param.Chain = Math.Max(param.Chain, context.Chain[player.ToInt()]); } Debug.Assert(context.FieldEvent[(int)player] == FieldEvent.None || context.FieldEvent[(int)player] == FieldEvent.End, "イベント発生中はありえません"); }