/// <summary> /// Determines which clues can be which blocks /// </summary> /// <remarks> /// Given a collection of blocks and a collection of clues, it is possible to determine that certain clues /// simply cannot be certain blocks (because they're too long or in the wrong place) /// This is all now done by the BlockIdentifier class. /// </remarks> public static void IdentifyBlocks(Grid grid, Clues clues, Blocks blocks, Spaces spaces, int element, int elementLength, bool isRow) { if (blocks.GetBlockCount() > 0 && clues.GetClueCount() > 0 && !clues.AllCluesSolved()) { BlockIdentifier bId = new BlockIdentifier(clues, blocks, spaces, elementLength); bId.IdentifyBlocks(); //now print the clues permitted for each block - this is for checking string outputstring; if (isRow) { Console.WriteLine("Row {0}, {1} clues and {2} blocks", element, clues.GetClueCount(), blocks.GetBlockCount()); } else { Console.WriteLine("Col {0}, {1} clues and {2} blocks", element, clues.GetClueCount(), blocks.GetBlockCount()); } for (int blockNo = 0; blockNo < blocks.GetBlockCount(); blockNo++) { outputstring = "Block : " + blockNo + ": "; for (int clueNo = 0; clueNo < clues.GetClueCount(); clueNo++) { if (blocks.GetBlock(blockNo).AllClues().ClueExists(clues.getClue(clueNo))) { outputstring += clueNo + ", "; } } Console.WriteLine(outputstring); } } }
/// <summary> /// A pretty simple method to check if there are certain cells that must be filled in regardless of clue position /// </summary> /// <remarks> /// If the clues are positioned as far left as they can go and then as far right as they can go there may be /// certain cells that will always be covered. /// For example, in an element of 15 cells a clue of length 10 will always cover cells 5 to 9 /// </remarks> private static int Overlap(Grid grid, Clues clues, Blocks blocks, Spaces spaces, int element, int elementLength, bool isRow) { int filled = 0; int firstFree = grid.GetFirstFreeCell(element, isRow); int lastFree = grid.GetLastFreeCell(element, isRow); int rowToUpdate; int colToUpdate; //For a given space, find the clues that HAVE to be in that space and check limits for (int spaceNo = 0; spaceNo < spaces.getSpaceCount(); spaceNo++) { Clues cluesToTest = FindFewestClues(spaces, clues, spaceNo); } for (int clueNo = 0; clueNo < clues.GetClueCount(); clueNo++) { //this needs adapted to take account of filled cells int endClueLeft = firstFree - 1 + clues.GetClueLength(0, clueNo); int startClueRight = lastFree + 1 - clues.GetClueLength(clueNo, clues.GetClueCount() - 1); if (startClueRight <= endClueLeft) { for (int cellNo = startClueRight; cellNo <= endClueLeft; cellNo++) { rowToUpdate = (isRow) ? element : cellNo; colToUpdate = (isRow) ? cellNo : element; if (Update(grid, colToUpdate, rowToUpdate, clues.getClue(clueNo).Colour)) { filled += 1; } } } } return(filled); }
/// <summary> /// Checks that the clue is entirely within a space (i.e. not opposite a cross square) /// </summary> private bool CluesFitInSpaces(Clues clues, Spaces spaces, int[] cluePositions) { for (int clueNo = 0; clueNo < clues.GetClueCount(); clueNo++) { if (!ClueFitsInSpace(clues.getClue(clueNo), spaces, cluePositions[clueNo])) { return(false); } } return(true); }
/// <summary> /// This class takes a Clues object, a Spaces object and a Blocks object and /// for each block determines which clues that block could legally be /// </summary> public BlockIdentifier(Clues clues, Blocks blocks, Spaces spaces, int elementLength) { _blocks = blocks; _clues = clues; _spaces = spaces; int clueCount = _clues.GetClueCount(); _cluePositions = new int[clueCount]; for (int i = 0; i < clueCount; i++) { _cluePositions[i] = elementLength - _clues.GetClueLength(i); } }
/// <summary> /// Deals with clues that are close to the edge of a spaces /// </summary> /// <remarks> /// Example: if we have a clue of length 3 as the first clue and cell 3 is filled in then cell 0 cannot be filled. /// Same can be done at the end of the element. /// </remarks> public static int EdgeProximity(Grid grid, Clues clues, Blocks blocks, Spaces spaces, int element, int elementLength, bool isRow) { int filled = 0; int rowToUpdate; int colToUpdate; bool atStart = true; int fillFrom = -1; int fillTo = -1; //Cross out cells which logically cannot be filled because there's too big a gap between the first block and the edge of the element. if (blocks.GetBlockCount() > 0 && clues.GetClueCount() > 0) { for (int loopCount = 0; loopCount < 2; loopCount++) { if (atStart && blocks.GetBlock(0).BlockColour == clues.getClue(0).Colour) { fillFrom = blocks.GetBlock(0).BlockStart - clues.getClue(0).Number; fillTo = fillFrom + blocks.GetBlock(0).BlockLength - 1; fillFrom = (fillFrom < 0) ? 0 : fillFrom; } else if (!atStart && blocks.GetBlock(blocks.GetBlockCount() - 1).BlockColour == clues.getClue(clues.GetClueCount() - 1).Colour) { fillFrom = blocks.GetBlock(blocks.GetBlockCount() - 1).BlockStart + clues.getClue(clues.GetClueCount() - 1).Number; fillTo = fillFrom + blocks.GetBlock(blocks.GetBlockCount() - 1).BlockLength; fillTo = (fillTo > elementLength - 1) ? elementLength - 1 : fillTo; } if ((fillFrom == 0 && fillTo >= 0) || (fillTo == elementLength && fillFrom <= elementLength)) { for (int cellNo = fillFrom; cellNo <= fillTo; cellNo++) { rowToUpdate = (isRow) ? element : cellNo; colToUpdate = (isRow) ? cellNo : element; if (Update(grid, colToUpdate, rowToUpdate, "cross")) { filled += 1; } } } atStart = false; } } return(filled); }
/// <summary> /// deals with the special case where there is only one clue. /// </summary> /// <remarks> /// This feels as though it should be able to be part of a different method. We'll see. /// </remarks> /// private static int SingleClue(Grid grid, Clues clues, Blocks blocks, Spaces spaces, int element, int elementLength, bool isRow) { int filled = 0; int blocksStart; int blocksEnd; int rowToUpdate; int colToUpdate; Clue clue; //we know there is only one clue. If there is more than one block then the space between them must be filled in. if (blocks.GetBlockCount() > 0 && clues.GetClueCount() == 1) { blocksStart = blocks.GetBlock(0).BlockStart; blocksEnd = blocks.GetBlock(blocks.GetBlockCount() - 1).BlockStart + blocks.GetBlock(blocks.GetBlockCount() - 1).BlockLength - 1; clue = clues.getClue(0); for (int cellNo = grid.GetFirstFreeCell(element, isRow); cellNo <= grid.GetLastFreeCell(element, isRow); cellNo++) { rowToUpdate = (isRow) ? element : cellNo; colToUpdate = (isRow) ? cellNo : element; if (cellNo >= blocksStart && cellNo <= blocksEnd) { if (Update(grid, colToUpdate, rowToUpdate, clue.Colour)) { filled += 1; } } else if (cellNo < blocksEnd - clue.Number + 1 || cellNo > blocksStart + clue.Number - 1) { if (Update(grid, colToUpdate, rowToUpdate, "cross")) { filled += 1; } } } } return(filled); }