Skip to content

Instantly share code, notes, and snippets.

@StephenFrey
Created March 30, 2020 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StephenFrey/d4ce9d7fdf2fb0b9bb269fa5473e3c7c to your computer and use it in GitHub Desktop.
Save StephenFrey/d4ce9d7fdf2fb0b9bb269fa5473e3c7c to your computer and use it in GitHub Desktop.
Omz forum post- mibradoc -translated
# 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