def startCells( self, nFilled=None, symRules=None, ): """ Find legal list of cells Sets data To provide atleast 2-way symitry with an odd lengthed board, one adds an "odd" cell to the board center cell :returns: list of CellDesc """ if nFilled is None: raise SelectError("startList nFilled is missing") if symRules is None: symRules = "c" symRules = symRules.lower() sym_c = True if re.search(r'c', symRules) else False sym_x = True if re.search(r'x', symRules) else False sym_y = True if re.search(r'y', symRules) else False nf = 0 # Number filled start_cells = [] # List of start cells in order if nFilled % 2 != 0 and (self.nRow % 2 == 1 or self.nCol % 2 == 1): crow = int((self.nRow + 1) / 2) ccol = int((self.nCol + 1) / 2) self.setCellVal(crow, ccol, 1) start_cells.append(CellDesc(row=crow, col=ccol)) nf += 1 while nf < nFilled: row = randint(1, self.nRow) col = randint(1, self.nCol) r_c = self.getNextEmpty(row=row, col=col) if r_c is None: break row = r_c.row # Update iff necessary col = r_c.col if sym_c: srow, scol = self.symCell(symRule='c', row=row, col=col) if self.isEmptyCell(srow, scol): self.setCellVal(srow, scol, 1) start_cells.append(CellDesc(row=srow, col=scol)) nf += 1 # Add original if not there if (self.isEmptyCell(row, row)): self.setCellVal(row, col, 1) start_cells.append(CellDesc(row=row, col=col)) nf += 1 return start_cells
def getNextEmpty(self, cd=None, row=None, col=None): # Returns: cell descriptor, else None if cd is not None or row is not None: self.curCell(cd=cd, row=row, col=col) cell = self.curCell() row = cell.row col = cell.col if (self.isEmptyCell(cell.row, cell.col)): self.advanceCell() if self.isEmptyCell(cell.row, cell.col): return cell ncell = self.nRow * self.nCol ntry = 0 if SlTrace.trace("empty"): SlTrace.lg("getNextEmpty()") while True: cd = self.advanceCell() row, col = cd.row, cd.col if SlTrace.trace("empty"): SlTrace.lg(f" getNextEmpty check row={row}, col={col}") ntry += 1 val = self.getCellVal(row, col) if self.isEmpty(val): SlTrace.lg(f"getNextEmpty - got row={row}, col={col}", "empty") return CellDesc(row=row, col=col) # Return empty cell descriptor if ntry >= ncell: SlTrace.lg("getNextEmpty - NONE FOUND") return None
def getCell(self, row=None, col=None, quiet=False): """ get Sudoku cell may be EMPTY :row: # 1-nRow :col: # 1-nCol :quiet:, # supress trace and cell movement default: False :returns: cell """ val = self.vals.getCellVal(row=row, col=col) return CellDesc(row=row, col=col, val=val)
def curCell(self, cd=None, row=None, col=None): # Returns: r_c ref to cell structure if cd is not None and (row is not None or col is not None): raise SelectError( "curCell: cd and row,col specified - allow only cd or row,col") if cd is None and row is None and col is None: return CellDesc(row=self.curRow, col=self.curCol) if cd is not None: self.curRow = cd.row self.curCol = cd.col return cd self.curRow = row self.curCol = col return CellDesc(row=self.curRow, col=self.curCol)
def setData(self, r_ds=None): """Set data clear if no data array :r_ds: array """ if self.cells is not None: # Clear del self.cells self.cells = [[ CellDesc(row=ri + 1, col=ci + 1) for ci in range(self.nCol) ] for ri in range(self.nRow)] if r_ds is not None: for ic in range(self.nRow): for ir in range(self.nCol): clds = r_ds[ir][ic] self.cells[ir][ic] = clds.copy()
def advanceCell(self): # Returns CellDesc array (row,col) """ Advance to next data cell Current and only pattern is row1 col1->nCol, row2 col1->nCol, ... wrapping at nRow,nCol to row1,col1 curRow, curCol are updated :returns: CellDesc """ row = self.curRow col = self.curCol col += 1 if col > self.nCol: row += 1 col = 1 if row > self.nRow: row = 1 self.curRow = row self.curCol = col return CellDesc(row=row, col=col)