Solving End view puzzle on Python [closed]
Question
I am working on a solver for End View puzzle on Python. This is what I have so far.
I am sorry for the messy code, but I am new here. My problem are the rules. The whole generation and running etc. works fine.
Can someone give me any advise or help considering the rules?
import re
import sys
katia=0
def read_data(filename):
try: f = open(filename, "r")
except:
print "\nERROR: File %s not found.\nNow try to open input.txt..." % filename
try:
f = open("input.txt", "r")
except:
print "\nERROR: File 'input.txt' not found."
sys.exit(raw_input("Press enter to exit..."))
return [ map(int, condition) for condition in
[ re.findall(r'\d+', line) for line in f.readlines()]
#here comes the rules in which i am not sure
def check(tab, row, conditions):
# check left-side conditions
if (conditions[0][row] != 0):
if ( ( tab[row][0] != conditions[0][row]
and
tab[row][1] != conditions[0][row]
and
tab[row][2] !=conditions[0][row]
)
or
( tab[row][1] == conditions[0][row]
and
tab[row][0] != 0
)
or
( tab[row][2] == conditions[0][row]
and
(tab[row][0] != 0 or tab[row][1] != 0)
)
):
return 0
# right-side conditions
if (conditions[1][row] != 0):
if( ( tab[row][-1] != conditions[1][row]
and
tab[row][-2] != conditions[1][row]
and
tab[row][-3] !=conditions[1][row]
)
or
( tab[row][-2] == conditions[1][row]
and
tab[row][-1] != 0
)
or
( tab[row][-3] == conditions[1][row]
and
( tab[row][-1] != 0 or tab[row][-2] != 0)
)
):
return 0
if row < (len(tab) - 3): # chek 3 below rows to uniqueness for uper numbers
for i in range(len(tab)):
if conditions[3][i] != 0:
if tab[row][i]==conditions[3][i]:
return 0
# check top-side conditions
if row == 1:
for col in range(len(tab)):
if conditions[2][col] != 0 :
if ( tab[1][col] == conditions[2][col]
and
( tab[2][col] == conditions[2][col]
and
tab[0][col] != 0 or tab[0][col] != 7
and
tab[1][col] != 0 or tab[1][col] != 7 )
or
( tab[0][col] != conditions[2][col]
and tab[1][col] != conditions[2][col]
and tab[2][col] != conditions[2][col] )
):
return 0
if row == 2:
for col in range(len(tab)):
if conditions[2][col] != 0:
if ( tab[1][col] != conditions[2][col]
and
tab[2][col] != conditions[2][col]
):
return 0
# check bottom-side conditions
if row == len(tab)-2:
for col in range(len(tab)):
if conditions[3][col] != 0:
if ( ( tab[-1][col] != conditions[3][col]
)
or
( tab[-2][col] == conditions[3][col]
and
tab[-1][col] == 0
)
):
return 0
if row == len(tab)-3:
for col in range(len(tab)):
if conditions[3][col] != 0:
if ( tab[-3][col] != conditions[3][col]
and
tab[-1][col] == 0
and
tab[-2][col] == 0
):
return 0
global katia
katia+=1
# check cols
for col in range(len(tab)):
for digit in range(1,4):
if( ([tab[i][col] for i in range(len(tab))].count(digit) > 1)
):
if katia%5000 == 0:
print "errrrror in %d: " % col,
print [tab[i][col] for i in range(len(tab))]
return 0
for col in range(len(tab)):
for digit in range(len(tab)):
if (( [tab[i][col] for i in range(len(tab))].count(digit)==0
and digit != 0 and digit !=7)
or
([tab[i][col] for i in range(len(tab))].count(digit) > 1
and digit not in range(1,7))
or
([tab[i][col] for
i in range(len(tab))].count(0)+ [tab[i][col]
for i in range(len(tab))].count(7) != 2)
):
return 0
katia++1
if katia/500 == 0:
for i in range(7):
print tab[i]
return 1
def generate(row):
if (row[0] == -1):
row[:] = range(len(row))
return 1
a = -1
for j in reversed(range(len(row)-1)):
if (row[j] < row[j+1]):
a = j
break
if a == -1:
return 0
b = -1
for j in reversed(range(a, len(row))):
if (row[j] > row[a]):
b = j
break
row[a], row[b] = row[b], row[a]
row[(a+1):] = reversed(row[(a+1):])
return 1
def rekurs(tab, row, conditions):
while (1):
if (generate(tab[row]) == 0):
tab[row] = [-1 for i in range( len(tab) )]
return 0
if check(tab, row, conditions) == 1:
if row < 7:
if (rekurs(tab, row+1, conditions)):
return 1
else:
return 1
## -------------------- run program -------------------
if __name__ == '__main__':
conditions = read_data(raw_input("Input file: "))
tab = [ [-1 for j in range(len(conditions[0]))]
for i in range( len(conditions[0]) ) ]
print "\nSuccess. \nNow search for solutions..."
if rekurs(tab, 0, conditions) == 0:
print "\nThere is no solution:"
for i in range(len(tab)): print tab[i]
else:
print "\nGood news:"
for i in range(len(tab)): print tab[i]
raw_input("Press enter to exit...")
After running the code, you have to add name of inputfile, which should contain restraints:
0 4 2 6 1 0 5 0
0 6 5 0 5 4 3 0
0 1 6 2 3 2 0 0
1 3 5 4 2 3 6 6
Solution
I have completed this task:here it is # -- coding: cp1251 -- import re import sys
iterations = 0 # переменная для подсчета итераций (используется при выводе)
# ------------------------------------------------------------------------------------
# Функция считывания условий из файла
def read_data(filename):
try: f = open(filename, "r")
except:
print "\nERROR: File %s not found.\nNow try to open input.txt..." % filename
try:
f = open("input.txt", "r")
except:
print "\nERROR: File 'input.txt' not found."
sys.exit(raw_input("Press enter to exit..."))
return [ map(int, condition) for condition in # для каждой "строки(массива)" массива
# каждый элемент превращаем в число.
[ re.findall(r'\d+', line) for line in f.readlines()]
] # для каждой линии из считанного файла
# регулярным выражением выделяем массив чисел в
# этой строке, которые разделены пробелом.
# ------------------------------------------------------------------------------------
# Функция проверки условий
def check(tab, row, conditions):
# Вывод матрицы на итерации с шагом 1000
global iterations
iterations +=1
if iterations % 1000000 == 0 :
for i in range(8):
print tab[i]
print " "
#Обязательное правило №1 #top-side conditions
# Проверка строк на соответствие верхним ограничениям
# Проверка первой строки
# Тут могут быть либо нули, либо ограничивающая цифра, иначе выход на перегенерацию строки
if row == 0:
for col in range(8):
if (conditions[2][col] != 0):
if (tab[0][col] != conditions[2][col] and
tab[0][col] != 0 and
tab[0][col] != 7
): # Грустный смайлик. Почему, ведь всё прекрасно работает?
return 0
# Если в первой строке нули, то во второй должно быть верхнее ограничение, либо ноль
if row == 1:
for col in range(8):
if (conditions[2][col] != 0):
if (
(tab[0][col] == 0 or tab[0][col] == 7) and
tab[1][col] != conditions[2][col] and
tab[1][col] != 0 and
tab[1][col] != 7
):
return 0
# Если в первой и второй строках нули, то в третьей должно быть верхнее ограничение, без вариантов
if row == 2:
for col in range(8):
if (conditions[2][col] != 0):
if (
(tab[0][col] == 0 or tab[0][col] == 7) and
(tab[1][col] == 0 or tab[1][col] == 7) and
tab[2][col] != conditions[2][col]
):
return 0
#Обязательное правило №2 #left-side conditions
# Проверка строк на соответствие левым ограничениям, вызывается для каждой строки
if (conditions[0][row] != 0): # если первое условин не нулевое. Какое первое? Левое! Первое оно у нас в файле, зачем привязывать к формату
if (
(tab[row][0] != conditions[0][row] and # если на первой позиции не стоит граничное
tab[row][1] != conditions[0][row] and #если на второй тоже не стоит граничное
tab[row][2] != conditions[0][row] #если на 3-й тоже не стоит граничное
)
or
(tab[row][1] == conditions[0][row] and # вторая позиция равна условию
(tab[row][0] != 0 and tab[row][0] != 7) # при этом на 1-й позиции не 0 и не 7
)
or
(
tab[row][2] == conditions[0][row] and
(
tab[row][0] != 0 and tab[row][0] != 7
or
tab[row][1] != 0 and tab[row][1] != 7
)
)
):
return 0
#Обязательное правило №3 #right-side conditions
# Проверка строк на соответствие правым ограничениям, вызывается для каждой строки
if (conditions[1][row] != 0):
if (
(tab[row][-1] != conditions[1][row] and # если на первой позиции не стоит граничное
tab[row][-2] != conditions[1][row] and #если тут тоже не стоит граничное
tab[row][-3] != conditions[1][row]
)
or
(tab[row][-2] == conditions[1][row] and
tab[row][-1] != 0 and tab[row][-1] != 7
)
or
(
tab[row][-3] == conditions[1][row] and
(
tab[row][-1] != 0 and tab[row][-1] != 7
or
tab[row][-2] != 0 and tab[row][-2] != 7
)
)
):
return 0
#Необязательное правило #Оптимизация
# Проверка того, что числа в нижних ограничениях не встречаются раньше 5-й строки
if row < (len(tab) - 3): # 8 - 3 = 5
for i in range(len(tab)):
if tab[row][i]==conditions[3][i]:
return 0
#Обязательные правила №5-6, переставлены сюда для оптимизации
# Проверка того, что цифры в столбце не повторились и что количество пробелов не больше 2
for j in range(0, row) :
for h in range(0, 8):
if (tab[row][h] == tab[j][h] and tab[row][h] != 0 and tab[row][h] != 7) :
return 0
sum = 0
for k in range(0, 8) :
for n in range(0, row + 1):
if (tab[n][k] == 0 or tab[n][k] == 7) :
sum += 1
if (sum > 2):
return 0
sum = 0
#Обязательное правило №4 #down-side conditions
# Проверка строк на соответствие нижним ограничениям (ТОДО: исправить и проверить)
if (row == 7):
for col in range(len(tab)):
if conditions[3][col] != 0 : #если 3-е условие не равно 0. Не 3-е, нижнее ведь. Давайте не будем путать людей
if (
(tab[-1][col] != conditions[3][col] and # Исправил индексы так, чтобы они были единой системы счисления
tab[-2][col] != conditions[3][col] and
tab[-3][col] != conditions[3][col]
)
or
(tab[-2][col] == conditions[3][col] and
tab[-1][col] !=0 and tab[-1][col] !=7
)
or
(
tab[-3][col] == conditions[3][col] and
(
tab[-1][col] !=0 and tab[-1][col] !=7
or
tab[-2][col] !=0 and tab[-2][col] !=7
)
)
):
return 0
return 1
# ------------------------------------------------------------------------------------
# Функция генерирования строки (почти без комментариев, потому что поздно)
def generate(row):
if (row[0] == -1):
row[:] = range(len(row))
return 1
a = -1
for j in reversed(range(len(row)-1)):
if (row[j] < row[j+1]):
a = j
break
if a == -1:
return 0
b = -1
for j in reversed(range(a, len(row))):
if (row[j] > row[a]):
b = j
break
row[a], row[b] = row[b], row[a] # Обмен значений для получения новой строки
row[(a+1):] = reversed(row[(a+1):])
return 1
# ------------------------------------------------------------------------------------
# Функция рекурсивного подбора строк матрицы
def rekurs(tab, row, conditions):
while (1):
if (generate(tab[row]) == 0): # Если не осталось больше вариантов строк - забиваем минус единицы, выходим
tab[row] = [-1 for i in range(len(tab))]
return 0
if (check(tab, row, conditions) == 1):
if row < 7: # Пока не заполним таблицу полностью, спускаемся по уровням, т.е. по строкам
if (rekurs(tab, row + 1, conditions)):
return 1
else:
return 1
## -------------------- run program -------------------
if __name__ == '__main__':
conditions = read_data(raw_input("Input file: "))
tab = [ [-1 for j in range(len(conditions[0]))] for i in range( len(conditions[0]) ) ]
print "\nSuccess. \nNow search for solutions..."
if rekurs(tab, 0, conditions) == 0:
print "\nThere is no solution:"
for i in range(len(tab)): print tab[i]
else:
print "\nGood news:"
for i in range(len(tab)):
for k in range(len(tab)):
if (tab[i][k] == 7): tab[i][k] = 0
print tab[i]
raw_input("Press enter to exit...")
And here is input file:
2 2 3 0 4 2 6 0
5 1 0 6 1 0 0 4
0 1 5 3 4 6 2 0
0 6 4 5 2 4 3 0
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow