protected override void CheckingNewRevealed(Vector2Int currentnewrevealed) { //count the number of neighbores of this tile List <Vector2Int> newClosedHiddenNeighbors = new List <Vector2Int>(); ClosedHiddenNeighbores.Add(currentnewrevealed, newClosedHiddenNeighbors); for (int j = 0; j < Operators.Length; j++) { Vector2Int current = currentnewrevealed + Operators[j]; if (Flaged.Contains(current)) { Closed[currentnewrevealed]--; } else if (MinesweeperElementInfo.InBounds(current, BoardSize.x, BoardSize.y)) { if (Open.ContainsKey(current) || Safe.Contains(current) || Mine.Contains(current)) { newClosedHiddenNeighbors.Add(current); List <Vector2Int> clist = HiddenClosedRelations[current]; clist.Add(currentnewrevealed); } else if (!InvalidTiles[current.x, current.y] && !Closed.ContainsKey(current)) { Open.Add(current, 0); newClosedHiddenNeighbors.Add(current); List <Vector2Int> clist = new List <Vector2Int>(); HiddenClosedRelations.Add(current, clist); clist.Add(currentnewrevealed); } } } }
protected bool NextToInvalidTile(Vector2Int tile) { int maxx = BoardSize.x; int maxy = BoardSize.y; for (int i = 0; i < Operators.Length; i++) { Vector2Int current = tile + Operators[i]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy) && InvalidTiles[current.x, current.y]) { return(true); } } return(false); }
GetRequestedMinesweeperElementInfos(MinesweeperGamestate gamestate, KeyValuePair <AIDataType, Vector2Int[]>[] request) { KeyValuePair <AIDataType, KeyValuePair <Vector2Int, MinesweeperElementInfo>[]>[] newanswer = new KeyValuePair <AIDataType, KeyValuePair <Vector2Int, MinesweeperElementInfo>[]> [request.Length]; for (int i = 0; i < request.Length; i++) { KeyValuePair <Vector2Int, MinesweeperElementInfo>[] currentrequest = MinesweeperElementInfo.GetFilteredTiles(gamestate, request[i].Value); newanswer[i] = new KeyValuePair <AIDataType, KeyValuePair <Vector2Int, MinesweeperElementInfo>[]> ( request[i].Key, currentrequest ); } return(newanswer); }
private static Vector2Int[] OnReveal(MinesweeperGamestate tiles, Vector2Int tile, Vector2Int[] operators) { //creating local variable resuting in mminimal performance boost int maxx = tiles.LengthX; int maxy = tiles.LengthY; List <Vector2Int> NeedUpdate = new List <Vector2Int>(); List <Vector2Int> opentiles = new List <Vector2Int>(); if (tiles[tile].hidden && !tiles[tile].flaged) { if (tiles[tile].value == 0) { opentiles.Add(tile); } else if (tiles[tile].value >= 9) { Debug.Log("Game Over"); tiles.GameOver = true; } tiles[tile].hidden = false; NeedUpdate.Add(tile); } while (opentiles.Count != 0) { for (int i = 0; i < operators.Length; i++) { Vector2Int current = opentiles[0] + operators[i]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy)) { if (tiles[current].hidden) { tiles[current].hidden = false; NeedUpdate.Add(current); if (tiles[current].value == 0) { opentiles.Add(current); } } } } opentiles.RemoveAt(0); } return(NeedUpdate.ToArray()); }
private int GetSpriteId(MinesweeperElementInfo msei) { if (msei.hidden) { if (msei.flaged) { return(10); } else { return(9); } } else { return(msei.value >= 9 ? 12 : msei.value); } }
/// <summary> /// Iterates through 'currentnewrevealed', checking if 'currentnewrevealed' can be discarded, /// while adding new open tile /// </summary> /// <param name="currentnewrevealed"></param> protected virtual void CheckingNewRevealed(Vector2Int currentnewrevealed) { for (int j = 0; j < Operators.Length; j++) { Vector2Int current = currentnewrevealed + Operators[j]; if (Flaged.Contains(current)) { Closed[currentnewrevealed]--; } else if (MinesweeperElementInfo.InBounds(current, BoardSize.x, BoardSize.y)) { //i wanted to make the minesweeper and the solver independent from eachother, thats why i didn't simply passed the minesweeperelementinfo object at 'current' tile if (!InvalidTiles[current.x, current.y] && !Open.ContainsKey(current) && !Closed.ContainsKey(current) && !Safe.Contains(current) && !Mine.Contains(current)) { Open.Add(current, 0); } } } }
/// <summary> /// Updates only the tiles directly affected by an action, send List of needed elements /// (Only for when revealing new tiles) /// </summary> /// <param name="toupdate">Information about newly revealed tiles</param> /// <param name="mat">The newly revealed tiles of the minesweeper table</param> public override void GetRelevantBoard(KeyValuePair <Vector2Int, MinesweeperElementInfo>[] toupdate, MinesweeperActionType mat) { if (mat == MinesweeperActionType.Uncover) { for (int i = 0; i < toupdate.Length; i++) { //note that every item in toupdate are revealed Vector2Int currentnewrevealed = toupdate[i].Key; MinesweeperElementInfo currentmsei = toupdate[i].Value; //there is always a possibility that the newly revealed tiles are in Open or Safe (when multiple tiles revealed) RemoveForSafety(currentnewrevealed); //add non-empties to 'Closed' if (currentmsei.value != 0) { Closed.Add(currentnewrevealed, currentmsei.value); //iterating through currently revealed tile, finding new tiles while trying to eliminate currentnewrevealed CheckingNewRevealed(currentnewrevealed); //remove from closed if after iteration value become 0 or less if (Closed[currentnewrevealed] <= 0) { WhenRemovingClosedNeighborCheck(currentnewrevealed); } } else { InvalidTiles[currentnewrevealed.x, currentnewrevealed.y] = true; } } } else if (mat == MinesweeperActionType.Flag) { for (int i = 0; i < toupdate.Length; i++) { Vector2Int currentmine = toupdate[i].Key; OnAddingFlaged(currentmine); } } }
/// <summary> /// This method was used before Invalidtiles /// </summary> /// <param name="answer">Data received from AIRequestProvider.GetRequestedMinesweeperElementInfos method</param> public void AnswerProcecessor(KeyValuePair <AIDataType, KeyValuePair <Vector2Int, MinesweeperElementInfo>[]>[] answer) { for (int i = 0; i < answer.Length; i++) { AIDataType requestType = answer[i].Key; KeyValuePair <Vector2Int, MinesweeperElementInfo>[] currentanswer = answer[i].Value; for (int j = 0; j < currentanswer.Length; j++) { Vector2Int currenttile = currentanswer[j].Key; MinesweeperElementInfo currentmsei = currentanswer[j].Value; if (currentmsei.hidden) { switch (requestType) { case AIDataType.Open: { //for safety, i only allow tiles to be considered safe if they were previusly open //so here i check if they belong to 'Safe' if (NextToInvalidTile(currenttile)) { Safe.Add(currenttile); } else { Open.Add(currenttile, 0); } break; } case AIDataType.Safe: { Safe.Add(currenttile); break; } } } } } }
/// <summary> /// Checks the whole board /// </summary> /// <param name="table"> The whole minesweeper table</param> public override void GetBoard(MinesweeperElementInfo[,] table) { List <Vector2Int> newpositions = new List <Vector2Int>(); for (int y = 0; y < table.GetLength(1); y++) { for (int x = 0; x < table.GetLength(0); x++) { MinesweeperElementInfo current = table[x, y]; Vector2Int currentpos = new Vector2Int(x, y); if (!current.hidden && current.value > 0) { if (!Closed.ContainsKey(currentpos)) { newpositions.Add(currentpos); } } } } for (int i = 0; i < newpositions.Count; i++) { for (int j = 0; j < Operators.Length; j++) { Vector2Int current = newpositions[i] + Operators[j]; //in bounds if (current.x >= 0 && current.y >= 0 && current.x < table.GetLength(1) && current.y < table.GetLength(0)) { if (table[current.x, current.y].hidden && !table[current.x, current.y].flaged && !Open.ContainsKey(current)) { Open.Add(current, 0); } } } Closed.Add(newpositions[i], table[newpositions[i].x, newpositions[i].y].value); } }
/// <summary> /// The first action commited by the player /// </summary> /// <param name="tiles"></param> /// <param name="firststep"></param> /// <param name="rule"></param> /// <param name="operators"></param> public static Vector2Int[] FirstOnReveal(MinesweeperGamestate tiles, Vector2Int firststep, MinesweeperFirstStepRule rule, Vector2Int[] operators) { //creating local variable resuting in miminimal performance boost int maxx = tiles.LengthX; int maxy = tiles.LengthY; if (rule == MinesweeperFirstStepRule.SafeSouranding) { //finding the 'safe tiles' List <Vector2Int> safe = new List <Vector2Int>(); for (int i = 0; i < operators.Length; i++) { Vector2Int current = firststep + operators[i]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy)) { safe.Add(current); } } safe.Add(firststep); //remove mines from 'safe tiles' List <Vector2Int> bombpositions = new List <Vector2Int>(); for (int i = 0; i < safe.Count; i++) { if (tiles[safe[i]].value >= 9) { tiles[safe[i]].value = 0; bombpositions.Add(safe[i]); } } //recalculate value of mines inside, and the souranding of 'safe' tiles for (int i = 0; i < bombpositions.Count; i++) { for (int j = 0; j < operators.Length; j++) { Vector2Int current = bombpositions[i] + operators[j]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy)) { if (tiles[current].value >= 9) { tiles[bombpositions[i]].value++; } else if (!bombpositions.Contains(current)) { tiles[current].value--; } } } } //reassigning mines [not fixed time], but faster List <Vector2Int> newbombs = new List <Vector2Int>(); while (bombpositions.Count != newbombs.Count) { Vector2Int current = new Vector2Int(Random.Range(0, maxx), Random.Range(0, maxy)); if (tiles[current].value < 9 && !safe.Contains(current)) { tiles[current].value = 9; newbombs.Add(current); } } //recalculate souranding of the new mines for (int i = 0; i < newbombs.Count; i++) { for (int j = 0; j < operators.Length; j++) { Vector2Int current = newbombs[i] + operators[j]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy)) { tiles[current].value++; } } } } else if (rule == MinesweeperFirstStepRule.SafeTile) { //firststep if (tiles[firststep].value >= 9) { tiles[firststep].value = 0; //recalculate value of firststep, and it's souranding for (int i = 0; i < operators.Length; i++) { Vector2Int current = firststep + operators[i]; if (MinesweeperElementInfo.InBounds(current, maxx, maxy)) { if (tiles[current].value >= 9) { tiles[firststep].value++; } else { tiles[current].value--; } } } //reassigning mine, and recalculate it's souranding while (true) { Vector2Int current = new Vector2Int(Random.Range(0, maxx), Random.Range(0, maxy)); if (tiles[current].value < 9 && current != firststep) { tiles[current].value = 9; for (int i = 0; i < operators.Length; i++) { Vector2Int current2 = current + operators[i]; if (MinesweeperElementInfo.InBounds(current2, maxx, maxy)) { tiles[current2].value++; } } break; } } if (tiles[firststep].value >= 9) { throw new System.Exception(); } } } return(OnReveal(tiles, firststep, operators)); }
void Update() { if (Input.GetKeyDown(KeyCode.LeftShift)) { InfoPanel.SetActive(!InfoPanel.activeInHierarchy); } if (!useai) { if (Input.GetMouseButtonDown(0)) { MinesweeperInteractionManager.OnStep(new KeyValuePair <MinesweeperActionType, Vector2Int>(MinesweeperActionType.Uncover, new Vector2Int(updatepos.x, -updatepos.y + settings.y - 1)), gamestate, settings.Operators); vh.UpdateVisualMinesweeperComplete(gamestate); } else if (Input.GetMouseButtonDown(1)) { MinesweeperInteractionManager.OnStep(new KeyValuePair <MinesweeperActionType, Vector2Int>(MinesweeperActionType.Flag, new Vector2Int(updatepos.x, -updatepos.y + settings.y - 1)), gamestate, settings.Operators); vh.UpdateVisualMinesweeperComplete(gamestate); } } if (sampleindex <= samplesize) { currenttime = updatetime; } while (useai && currenttime >= 0 && !requireclick) { if (!gamestate.GameOver) { Vector2Int[] needtobeupdated; KeyValuePair <MinesweeperActionType, Vector2Int> aistep = af.ChooseStep(); //Debug.Log(aistep); if (gamestate.FirstStep) { needtobeupdated = MinesweeperInteractionManager.FirstOnReveal(gamestate, aistep.Value, settings.FirstStepRule, settings.Operators); gamestate.FirstStep = false; } else { needtobeupdated = MinesweeperInteractionManager.OnStep(aistep, gamestate, settings.Operators); } //update database, and request tiles af.GetRelevantBoard(MinesweeperElementInfo.GetFilteredTiles(gamestate, needtobeupdated), aistep.Key); //answer to requested tiles //KeyValuePair<AIRequestType, KeyValuePair<Vector2Int, MinesweeperElementInfo>[]>[] answertiles = AIRequestProvider.GetRequestedMinesweeperElementInfos(gamestate, requestedtiles); //update database with requested tiles //af.AnswerProcecessor(answertiles); vh.UpdateVisualMinesweeperQuick(MinesweeperElementInfo.GetFilteredTiles(gamestate, needtobeupdated)); } if (sampleindex <= samplesize) { if (gamestate.GameOver) { NewGame(); SetUpSolver(); } else if (af.Flaged.Count == settings.NumberOfMines) { samplewins++; NewGame(); SetUpSolver(); } } if (ClickToStep) { requireclick = true; } currenttime -= Time.deltaTime; } //helps to see the current state of the game if (useai && settings.Rendering) { Vector2Int[] v2is = af.InvalidTiles.GetPositions(true); vh.HighlightTiles(af.Mine.ToArray(), AIDataType.Mine); vh.HighlightTiles(af.Safe.ToArray(), AIDataType.Safe); vh.HighlightTiles(af.Open.Keys.ToArray(), AIDataType.Open); vh.HighlightTiles(af.Closed.Keys.ToArray(), AIDataType.Closed); vh.HighlightTiles(v2is, AIDataType.Invalid); vh.FinalizeUpdate(); } if (sleeptime > 0) { Thread.Sleep(sleeptime); } indextext.text = (sampleindex - 1).ToString(); wintext.text = samplewins.ToString(); //fps fpsText.text = ((int)(1.0f / Time.deltaTime)).ToString(); }