private void FixedAttack(){ var data = Model.Analize( Target.Clone() ); Output += Target.CurrentStep + ":\n" + data.BrokenCount; Output += "\n" + data.Score; Output += "\n" + data.MaxChain; Output += "\n" + data.Chain; Output += "\n" + string.Join(",", data.ChainSegs.Select(s => s.ToString()).ToArray()); Output += "\n" + data.BingoCount +"/"+ Model.BingoMax; if( (Game.DefaultBlocks.Length - Target.CurrentStep < FixedLimit && data.BingoCount == Model.BingoMax && !HaiteiMode) || Game.DefaultBlocks.Length - Target.CurrentStep < 25 ){ FixedMode = false; FinishFix = Target.Clone(); Attack(); return; } var futures = new List<Future>(); Block b = Game.DefaultBlocks[ Target.CurrentStep ]; int w = Game.Width - Game.Size + 1; int rest = Game.DefaultBlocks.Length - Target.CurrentStep - 1; int depth = FixedDepth < rest ? FixedDepth : rest; for(int i = 0; i < Game.ROTATE_NUM; i++){ for(int j = -b.Left[i], jl = w + b.Right[i]; j < jl; j++){ Game clone = Target.Clone(); clone.Next(j,i); if( clone.GameOver ) continue; data = Model.Analize( clone.Clone() ); var move = new Move(j, i); futures.Add( new Future( move, clone, data.Score ) ); } } futures = FixedReadFutures( futures, depth ); if( futures.Count == 0 ){ FixedMode = false; FinishFix = Target.Clone(); Attack(); }else{ futures.Sort(); var move = futures[0].Root; Output += "\n" + futures[0].Potaintial; Drop( move.Position, move.Rotate ); } }
public Future( Move root, Game target, double potaintial ){ Root = root; Target = target; Potaintial = potaintial; }
//評点 private double CalcPotaintial( Game game, Move move, int depth ){ double max = double.MinValue; Block b = Game.DefaultBlocks[ game.CurrentStep ]; int w = Game.Width - Game.Size + 1; //次のブロックを落下させてみる。 for(int i = 0; i < Game.ROTATE_NUM; i++ ){ for(int j = -b.Left[i], jl = w + b.Right[i]; j < jl; j++){ Game clone = game.Clone(); clone.Next(j,i); if( clone.GameOver ) continue; double score = clone.Score - game.Score; if( max < score ){ max = score; } } } if( ChainMaxScore <= max ){ ChainMaxScore = max; ChainMove = move; } if( depth <= 1 ) return max; int h0 = 0, h1 = 0, h2 = game.HeightList[0]; var cl = CheckList[ game.CurrentStep ]; int end = (Game.Sum-1); //連鎖テスト用のブロックを落下させてみる。 for( int x = 0; x < Game.Width; x++ ){ h0 = h1; h1 = h2; if( x + 1 < Game.Width ) h2 = game.HeightList[ x + 1 ]; else h2 = 0; for( int i = 0; i < CheckHeight; i++ ){ if( h0 <= h1 + i * HeightSpan && h2 <= h1 + i * HeightSpan ) break; for( int j = 0; j < end; j++ ){ if(! cl[ j ] ) continue; Game clone = game.Clone(); clone.Drop( CheckBlocks[i,j], x, 1, 0 ); clone.Kill(); if( clone.GameOver || clone.LastChain == 0 ) continue; double score = (clone.Score - game.Score); if( max < score ) max = score; } } } return max; }
//先読みする手を足切り点付きで枝刈り、残りの手が1種類になったら、True。 protected static bool Prune( List<Future> futures, Move currentMove, int width, double minScore ){ futures.Sort(); int l = futures.Count; if( l > width ){ futures.RemoveRange( width, l - width ); l = width; } for( int i = 0; i < l; i++ ) if( futures[i].Potaintial < minScore ){ futures.RemoveRange(i, l - i); l = i; break; } for( int i = 0; i < l; i++ ) if( currentMove != futures[i].Root ) return false; return true; }
//不定型連鎖を組む。 public void Attack(){ var futures = new List<Future>(); Block b = Game.DefaultBlocks[ Target.CurrentStep ]; int w = Game.Width - Game.Size + 1; int rest = Game.DefaultBlocks.Length - Target.CurrentStep - 1; int depth = Depth < rest ? Depth : rest; double baseScore = Target.Score; FireMax = ChainMaxScore = double.MinValue; for(int i = 0; i < Game.ROTATE_NUM; i++) for(int j = -b.Left[i], jl = w + b.Right[i]; j < jl; j++){ Game clone = Target.Clone(); clone.Next(j,i); if(! clone.GameOver ){ double score = clone.Score - baseScore; var move = new Move( j, i, score ); if( FireMax <= score ){ FireMax = score; FireMove = move; } if( depth > 0 ) futures.Add( new Future( move, clone, CalcPotaintial(clone, move, depth) ) ); } } if( futures.Count == 0 ){ Fire(); return; } ReadFuture( futures, depth - 1 ); if( FireMax * FireRate > ChainMaxScore ) Fire(); else ChainUp(); }