public void ChainedExplosions() { Board board = CreateBoard(4, 3, new[] { // 0 1 2 3 Cube(1), Cube(1), Cube(3), Cube(1), // 0 Cube(1), Cube(1), Bomb(2), Cube(1), // 1 Ball(1), Ball(1), Cube(3), Bomb(1), // 2 }); var game = new Game(board); // IAction[] actions = game.Swap(new Point(2, 2), new Point(3, 2)); // Console.Out.WriteLine(game.Dump()); var dAct = (DestroyAction)actions[1]; var matchBomb = new Point(2, 2); var chainBomb = new Point(2, 1); // Assert.False(dAct.MatchDestroyedPos.Any(p => p.Pos == chainBomb)); Assert.AreEqual(3, dAct.MatchDestroyedPos.Length); Assert.True(dAct.MatchDestroyedPos.Any(p => p.Pos == new Point(0, 2))); Assert.True(dAct.MatchDestroyedPos.Any(p => p.Pos == new Point(1, 2))); Assert.True(dAct.MatchDestroyedPos.Any(p => p.Pos == matchBomb)); Assert.True(dAct.DestroyedBy.Keys.Any(p => p.Pos == matchBomb)); Assert.True(dAct.DestroyedBy.Keys.Any(p => p.Pos == chainBomb)); // Chain bomb explosion ItemPos matchBombPos = dAct.DestroyedBy .Keys .First(p => p.Pos == matchBomb); ItemPos chainBombPos = dAct.DestroyedBy .Keys .First(p => p.Pos == chainBomb); ItemPos[] byMatchBombPos = dAct.DestroyedBy[matchBombPos]; ItemPos[] byChainBombPos = dAct.DestroyedBy[chainBombPos]; // Assert.AreEqual(4, byMatchBombPos.Length); Assert.True(byMatchBombPos.Any(p => p.Pos == new Point(1, 1))); Assert.True(byMatchBombPos.Any(p => p.Pos == new Point(2, 1))); Assert.True(byMatchBombPos.Any(p => p.Pos == new Point(3, 1))); Assert.True(byMatchBombPos.Any(p => p.Pos == new Point(3, 2))); Assert.AreEqual(3, byChainBombPos.Length); Assert.True(byChainBombPos.Any(p => p.Pos == new Point(1, 0))); Assert.True(byChainBombPos.Any(p => p.Pos == new Point(2, 0))); Assert.True(byChainBombPos.Any(p => p.Pos == new Point(3, 0))); }
private void CollectBonusDestroy( ItemPos item, IDictionary <ItemPos, ItemPos[]> destroyedBy, ISet <Point> except) { var destroyed = new List <Point>(); if (item.Item.IsBombShape) { destroyed = GetBombNeighbour(item.Pos) .Except(except) .ToList(); } else if (item.Item.IsLineShape) { destroyed = GetLine(item.Pos, item.Item.Shape) .Except(except) .ToList(); } except.UnionWith(destroyed); // no more destroying for this ItemPos[] destroyedPositions = destroyed .Select(p => new ItemPos(p, Items[p.X, p.Y])) .ToArray(); destroyedBy[item] = destroyedPositions; // Recursively bonus destroyed foreach (ItemPos pos in destroyedPositions) { if (!pos.Item.IsRegularShape) { CollectBonusDestroy(pos, destroyedBy, except); } } }
public IAction[] CheatBonus(ItemShape bonus) { var rnd = new Random(); bool vertical; switch (bonus) { case ItemShape.HLine: vertical = false; break; case ItemShape.VLine: vertical = true; break; default: vertical = rnd.Next(2) == 0; break; } ItemShape shape = rnd.Next(2) == 0 ? ItemShape.Ball : ItemShape.Cube; int color = rnd.Next(shape == ItemShape.Ball ? 3 : 2) + 1; int x = vertical ? rnd.Next(BoardWidth) : rnd.Next(BoardWidth - 3); int y = vertical ? rnd.Next(BoardHeight - 3) : rnd.Next(BoardHeight); Point[] place = PointsFrom(x, y, vertical, 3); // Needs to avoid NullReferenceException while destroy old bonuses var destroyedBy = new Dictionary <ItemPos, ItemPos[]>(); List <ItemPos> oldBonuses = place .Select(p => new ItemPos(p, Items[p.X, p.Y])) .Where(ip => ip.Item.IsBombShape || ip.Item.IsLineShape) .ToList(); oldBonuses.ForEach(b => destroyedBy[b] = new ItemPos[0]); // var dAct = new DestroyAction { MatchDestroyedPos = place .Select(p => new ItemPos(p, Items[p.X, p.Y])) .ToArray(), SpawnBonuses = new ItemPos[0], DestroyedBy = destroyedBy, }; Items[place[0].X, place[0].Y] = new Item(color, shape); Items[place[1].X, place[1].Y] = new Item(color, bonus); Items[place[2].X, place[2].Y] = new Item(color, shape); var spAct = new SpawnAction { Positions = place .Select(p => new ItemPos(p, Items[p.X, p.Y])) .ToArray(), }; return(new IAction[] { dAct, spAct }); }
private IEnumerable <IAction> ProcessMatch(Point src, Point dest, MatchRes match) { var actions = new List <IAction>(); // var regularDestroy = new HashSet <Point>(); match.MatchLines.ForEach(l => regularDestroy.UnionWith(l)); match.MatchCrosses.ForEach(cr => { (Point[] line1, Point[] line2) = cr; regularDestroy.UnionWith(line1); regularDestroy.UnionWith(line2); }); ItemPos[] regularDestroyPos = regularDestroy .Select(p => new ItemPos(p, Items[p.X, p.Y])) .ToArray(); // var bonuses = new List <ItemPos>(); match.MatchLines.ForEach(line => { ItemPos bonus = CalcBonusSpawn(src, dest, line); if (bonus != null && bonuses.All(b => b.Pos != bonus.Pos)) { bonuses.Add(bonus); } }); match.MatchCrosses.ForEach(cross => { ItemPos bonus = CalcBonusSpawn(src, dest, cross); if (bonus != null && bonuses.All(b => b.Pos != bonus.Pos)) { bonuses.Add(bonus); } }); var except = new HashSet <Point>(regularDestroy); // New modified set var destroyedBy = new Dictionary <ItemPos, ItemPos[]>(); regularDestroyPos .Where(p => !p.Item.IsRegularShape).ToList() .ForEach(p => CollectBonusDestroy(p, destroyedBy, except)); // UpdateBoardOnDestroy(regularDestroyPos, destroyedBy, bonuses); // actions.Add(new DestroyAction { MatchDestroyedPos = regularDestroyPos, SpawnBonuses = bonuses.ToArray(), DestroyedBy = destroyedBy, }); FallDownPos[] fallen = _board.CalcFallDownPositions().ToArray(); actions.Add(new FallDownAction { Positions = fallen }); ItemPos[] spawned = _board.SpawnItems().ToArray(); actions.Add(new SpawnAction { Positions = spawned }); return(actions); }