Created
March 30, 2020 09:43
-
-
Save StephenFrey/d4ce9d7fdf2fb0b9bb269fa5473e3c7c to your computer and use it in GitHub Desktop.
Omz forum post- mibradoc -translated
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 2020.03.30 | |
''' | |
@cvp | |
this a training code for the beginner that I am | |
the comments are in french, sorry. | |
I'm not fluent in english, as you can see | |
Once script launched you have to make an input. Enter 'libre' (that is the file 'libre.txt' coming with my script ) | |
The for loop is line # 141 | |
using breakpoint you 'll see the jump to line 147 after the first print | |
thank a lot for help | |
''' | |
''' | |
Detect for each digit cases where an exclusive alternative of two boxes appears in the same square on a row (column, then row) when that number is already in one of the other two rows of the analyzed rectangle. In this case, check if a single position can be deduced for this figure. If yes, the box so inferred is completed with this number | |
''' | |
import numpy as np | |
###################################################################### FONCTIONS - START ####### | |
# Function that extracts the sudoku to be resolved from a .txt file | |
def makepuzzle_from_txt(fi_txt): | |
puzzle=np.zeros((9,9),dtype=int) | |
with open(fi_txt)as fi: | |
a=fi.readlines() | |
for i in range (0,9): | |
puzzle_line=[] | |
for y in range(0,9): | |
puzzle_line.append(a[i][y]) | |
puzzle[i]=puzzle_line | |
return puzzle | |
# function that saves as a file.txt an array of 9X9 | |
def grid2txt(grid,fichier): | |
with open ( fichier + '.txt' , 'w') as fi: | |
for ligne in range (9): | |
row='' | |
for colonne in range(9): | |
row = row + str(grid[ligne,colonne]) | |
row=row+'\n' | |
fi.write(row) | |
# function that returns the number of the inner square to which a box belongs (row, column): | |
def numcarrint(ligne,colonne): | |
return (3 * (ligne // 3)) + (colonne // 3) | |
# function that returns the internal square array (0-8) requested by the function call: | |
def carrint(n): | |
return puzzle[ 3 * (n // 3) : 3 * (n // 3) + 3 , 3 * (n % 3) : 3 * (n % 3) + 3] | |
# function that returns the horizontal rectangle array (0-2) requested by the function call: | |
def rect_h(n): | |
return puzzle [ 3 * (n % 3) : 3 * (n % 3) + 3 , : 9 ] | |
# function that returns the array of the vertical rectangle (0 to 2) requested by the function call: | |
def rect_v(n): | |
return puzzle [ : 9 , 3 * ( n % 3 ) : 3 * ( n % 3 ) + 3 ] | |
def fn_cases_chiffres(puzzle): | |
cases_chiffres={} | |
for ligne in range (9): | |
for colonne in range(9): | |
chiffres_possibles_pour_cette_case=[] | |
if puzzle[ligne,colonne] == 0: | |
for chiffre in range(1,10): | |
if chiffre not in puzzle[ligne,:9] and chiffre not in puzzle[:9,colonne] and chiffre not in carrint(numcarrint(ligne,colonne)): | |
chiffres_possibles_pour_cette_case.append(chiffre) | |
cases_chiffres[(ligne,colonne)]=chiffres_possibles_pour_cette_case | |
return cases_chiffres | |
def fn_only2(): | |
only2={} | |
for key in cases_chiffres: | |
if len(cases_chiffres[key]) == 2 : | |
only2[key] = cases_chiffres[key] | |
return only2 | |
# Function that writes a number in a box and updates dictionaries | |
def fn_remplir_case ( ligne , colonne , chiffre ) : | |
puzzle [ ligne , colonne ] = chiffre | |
fn_cases_chiffres ( puzzle ) | |
fn_only2() | |
###################################################################### FONCTIONS - END ####### | |
###################################################################### CODE PRINCIPAL - START | |
# Choose the .txt file that contains the grid to be resolved via input below: | |
puzzle=makepuzzle_from_txt(input("grille à résoudre ? ")+".txt") | |
print() | |
print(puzzle) | |
print (len(fn_cases_chiffres(puzzle))) | |
boucle = 0 | |
############### Start of main loop | |
while True: | |
boucle += 1 | |
puzzle_start_boucle=np.copy(puzzle) | |
# Establish a dictionary of possible numbers for each empty box (cad that contains 0) by calling a function: | |
cases_chiffres=fn_cases_chiffres(puzzle) | |
#Find, for each number, the exclusive alternatives of two possible boxes on the same line of the same square. | |
# First in horizontal rectangles: Create a chiffre_ligne_colonnes dictionary Key - torque (figure, line) | |
# Value - columns of the two boxes of this line that would be in the same square and would be an exclusive alternative to accommodate the figure | |
chiffre_ligne_colonnes = {} | |
for chiffre in range ( 1 , 10): | |
for ligne in range ( 9 ) : | |
colonnes = [] | |
for colonne in range ( 9 ) : | |
if puzzle[ ligne , colonne ] == 0 : | |
if chiffre in cases_chiffres [ ligne , colonne ] : | |
colonnes.append ( (colonne) ) | |
if len(colonnes) == 2 : | |
if numcarrint(ligne,colonnes[0]) == numcarrint(ligne,colonnes[1]): | |
chiffre_ligne_colonnes[(chiffre,ligne)] = colonnes | |
# The dico chiffre_ligne_colonnes is here complete (and validated?) | |
#Of the other 2 lines in the horizontal rectangle, only one of the two should not contain key. | |
for key in chiffre_ligne_colonnes: | |
ligne_a_analyser = [] | |
for ligne in range(((key[1] // 3) * 3) , ((key[1] // 3) * 3) + 3) : | |
if ligne != key[1] and key[0] not in puzzle [ligne,:9] : | |
ligne_a_analyser.append(ligne) | |
if ligne_a_analyser != [] : | |
ligne_a_analyser = ligne_a_analyser[0] | |
print ( key , chiffre_ligne_colonnes[key] , ligne_a_analyser ) | |
# On this line, explore the three columns of the square that do not yet contain key[0]. If two of these 3 columns are already occupied, bingo, you can fill third with key[0] | |
# Find the number of the square that contains the exclusive alternative: | |
numcarre_altex = numcarrint(key[1],chiffre_ligne_colonnes[key][0]) | |
# the number of the 3 squares of a horizontal rectangle can be found by determining the number of the first by the formula (number of one of the three squares // 3) * 3 | |
# Here you have to find in the two squares other than numcarre_altex the one that does not contain key[0], and from there, the first of the three columns of this square | |
for numero_carre in range ( (numcarre_altex // 3) * 3,((numcarre_altex//3)*3) + 3 ) : | |
#print (numero_carre) # BUG !! exit of the for loop after 1st passage !! | |
if numero_carre != numcarre_altex and key[0] not in carrint(numero_carre) : | |
numero_carre_sans_chiffre = numero_carre | |
colonnes_possibles=[] | |
for colonne in range((numero_carre % 3)*3,(numero_carre % 3)*3 + 3) : | |
if puzzle[ ligne_a_analyser , colonne ] == 0 and key[0] not in puzzle[:9,colonne]: | |
colonnes_possibles.append(colonne) | |
if len(colonnes_possibles) == 1 : | |
fn_remplir_case ( ligne_a_analyser , colonnes_possibles[0] , key[0] ) | |
print() | |
print (puzzle) | |
print () | |
# Exit loop if puzzle has not been changed | |
if np.array_equal(puzzle,puzzle_start_boucle): | |
break | |
########### End of main loop | |
########### Final Report | |
print() | |
print(puzzle) | |
print(len(cases_chiffres)) | |
print(boucle) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment