Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define setBit(var, bit) var |= 1 << bit
#define checkBit(var, bit) var & (1 << bit)
enum { CLEAN = -1, LINE, ROW, SECTOR };
struct _cell {
uint8_t value, line, row, sector;
uint16_t used;
};
typedef struct _cell t_cell;
t_cell *checkBox[3][9][9];
t_cell sol[81];
int checkCell(int cell);
int
main(int argc, char **argv)
{
register int i, j = 0;
int u = 0;
memset(checkBox, 0, sizeof(checkBox));
memset(sol, 0, sizeof(sol));
/* Initialization */
for(i = 0; i < 81; i++) {
sol[i].line = i / 9;
sol[i].row = i % 9;
sol[i].sector = (((i / 9) / 3) * 3) + ((i % 9) / 3);
checkBox[LINE][i / 9][i % 9] = &sol[i];
checkBox[ ROW][i % 9][i / 9] = &sol[i];
while(checkBox[SECTOR][sol[i].sector][j])
++j;
checkBox[SECTOR][sol[i].sector][j] = &sol[i];
j = 0;
}
srand(time(NULL));
/* Generate solution */
for(i = 0; i < 81; i++) {
do {
do {
u = 0;
if(sol[i].used == 511) {
setBit(sol[i-1].used, (sol[i-1].value - 1));
sol[i].used = sol[i].value = 0;
i -= 2;
u = 1;
break;
}
sol[i].value = 1 + rand() % 9;
} while((checkBit(sol[i].used, (sol[i].value - 1))));
if(u)
break;
} while(checkCell(i) != CLEAN);
}
/* Display result */
for(i = 0; i < 9; i++) {
if(i%3 == 0)
printf("-------------------------\n");
printf("| %d %d %d | %d %d %d | %d %d %d |\n",
sol[i*9].value, sol[i*9+1].value, sol[i*9+2].value,
sol[i*9+3].value, sol[i*9+4].value, sol[i*9+5].value,
sol[i*9+6].value, sol[i*9+7].value, sol[i*9+8].value
);
}
printf("-------------------------\n");
return 0;
}
int
checkCell(int cell)
{
register int i;
int result = CLEAN;
for(i = 0; i < 9; i++) {
if(&sol[cell] != checkBox[LINE][sol[cell].line][i]) {
if(sol[cell].value == checkBox[LINE][sol[cell].line][i]->value)
result = LINE;
}
if(&sol[cell] != checkBox[ROW][sol[cell].row][i]) {
if(sol[cell].value == checkBox[ROW][sol[cell].row][i]->value)
result = ROW;
}
if(&sol[cell] != checkBox[SECTOR][sol[cell].sector][i]) {
if(sol[cell].value == checkBox[SECTOR][sol[cell].sector][i]->value)
result = SECTOR;
}
}
if(result != CLEAN) {
setBit(sol[cell].used, (sol[cell].value - 1));
}
return result;
}
sudoku_generator.Grid вместо sudoku_generator.grid.object — в Python 2 это избавит от неожиданностей в виде ограниченного поведения old-style classes, тогда как в Python 3 классы и так наследуются от object по-умолчанию.print(). Если требуется отладочный вывод, дайте возможность пользователю задать свой собственный print_callback в __init__-е: def __init__(self, n = 3, print_callback = lambda *args, **kwarg: None):
self.__print_callback = print_callback
...
self.__print_callback('The base table is ready!')
from __future__ import print_function в целях увеличения переносимости кода. Таким образом, print() станет функцией и код будет переносим между Python 2 и Python 3.class Grid(object):
n = property(lambda self: self.__n)
def __init__(self, n = 3):
self.__n = n
x / y там, где вам точно нужен целочисленный результат — используйте целочисленное деление x // y. from __future__ import division включит это поведение в Python 2 для облегчения перехода.sudoku_generator.Grid.__del__ кроме бесполезности, еще и немножко вреден — в зависимости от реализации, __del__ либо затрудняет, либо делает невозможной сборку мусора. В данном случае от метода лучше избавиться.for x in range(len(foo)): bar(foo[x]) как правило, можно заменить на for x in foo: bar(x).random.randrange не нужен третий аргумент, если он равен 1, и не нужен первый аргумент, если он равен 0, т.к. это значения по умолчанию. Таким образом, random.randrange(0, N, 1) равноценно random.randrange(N).xrange более эффективен, чем range, т.к. возвращает итератор, а не список, но в Python 3 range ведет себя, как xrange, а xrange не существует. Следует заменить все вхождения range(...) на list(range(...)), а xrange(...) на range(...), и постараться использовать range (бывший xrange) везде, где не используются методы list-а.if и while необязательны скобки вокруг условий.sudoku_generator.Grid.swap_rows_small цикл по выбору line2 может длиться сколько угодно долго, плюс имеет место дублирование кода. Возможно, было бы лучше переписать функцию следующим образом? def swap_rows_small(self):
r'''Swap two rows.
'''
# случайные разные строки в пределах района
line1, line2 = random.sample(range(self.__n), 2)
# получение случайного района
area = random.randrange(self.__n)
# строки для обмена
N1 = area * self.__n + line1
N2 = area * self.__n + line2
self.__table[N1], self.__table[N2] = self.__table[N2], self.__table[N1]
sudoku_generator.Grid.swap_rows_area: def swap_rows_area(self):
r'''Swap two area horizon.
'''
# случайные разные районы
area1, area2 = random.sample(range(self.__n), 2)
for i in range(self.__n):
N1, N2 = area1 * self.__n + i, area2 * self.__n + i
self.__table[N1], self.__table[N2] = self.__table[N2], self.__table[N1]
Grid.foo(self) лучше использовать прямой вызов self.foo().sudoku_generator.Grid.mix использует eval — это не очень хорошая идея, т.к. каждый вызов заново дергает компилятор со всей обвязкой. Вообще eval, compile и exec в прикладных задачах нужны, как правило, крайне редко. Функцию можно переписать следующим образом: def mix(self, amt = 10):
mix_func = (
self.transposing,
self.swap_rows_small,
self.swap_colums_small,
self.swap_rows_area,
self.swap_colums_area,
)
for i in range(amt):
random.choice(mix_func)()
array[random.randrange(len(array))] на прямой выбор элемента random.choice(array) — меньше промежуточных шагов и понятнее решение.tuple ((a, b, c)) вместо list ([a, b, c]) в статических структурах — там, где не потребуется последующая модификация. Это позволит компилятору уменьшить объем памяти, потребляемой структурой, и создавать ее единожды вместо пересоздания при каждом вызове mix()"-" * 10 == "----------", а "-*=" * 3 == "-*=-*=-*=".sudoku_generator лучше было бы сделать частью класса sudoku_generator.Grid.def transpose(self): '''Transpose grid''' вместо def transposing(self): '''Transposing grid''', таким образом, вызовы методов звучат, как действия.solver, похоже, принадлежит перу другого автора :) К нему претензий нет, написан очень хорошо.3. Избегайте использования прямых вызовов print(). Если требуется отладочный вывод, дайте возможность пользователю задать свой собственный print_callback в __init__-е: …Если использовать print только для отладочного вывода, то простого правила «всегда писать скобки после
4. Используйте from __future__ import print_function в целях увеличения переносимости кода. Таким образом, print() станет функцией и код будет переносим между Python 2 и Python 3.
print» достаточно для переносимости. Мне никогда не приходило в голову передавать print как функцию куда‐либо: для этого есть logging (имею ввиду передачу экземпляров logging.Logger, если имеющийся настраиваемый глобальный Logger чем‐то не нравиться). И вместо print_callback тоже есть logging.print» чревато этим:>>> print('Hello', 'world')
('Hello', 'world')
>>> from __future__ import print_function
>>> print('Hello', 'world')
Hello world
logging разумно, но это если нужно полноценное логгирование. Для целей отладки, как мне кажется, callback достаточно, но тут мы истины не найдем, т.к. любой подход хорош по своему.
Алгоритм генерации судоку