Автор Тема: Неархитектурная задачка  (Прочитано 43367 раз)

Губанов Сергей Юрьевич

  • Hero Member
  • *****
  • Сообщений: 590
    • Просмотр профиля
    • Домашняя страница
Re: Неархитектурная задачка
« Ответ #105 : Май 21, 2012, 11:12:20 am »
Решил прикинуть масштаб скорости 1С по отношению к КП
А Массив.Количество() -- это константа времени компиляции или функция? Похожа на функцию. Попробуй заменить на константу.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Неархитектурная задачка
« Ответ #106 : Май 21, 2012, 11:17:28 am »
Константа.

зы Я пробовал и без массивов просто присвоение переменной делать. Отношение все равно примерно 500:1

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Неархитектурная задачка
« Ответ #107 : Май 21, 2012, 11:24:32 am »
Хотя нет, не константа... туплю. Но вычисляется один раз при входе в цикл (ну как обычно в FOR).
К тому же массив в 1С знает свою длину. Т.е. этот метод дешевый и на результат очень слабо влияет.

Kemet

  • Hero Member
  • *****
  • Сообщений: 587
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #108 : Май 21, 2012, 06:08:25 pm »
Массивы в 1С основаны на коллекциях, поэтому совсем не удивителен результат.

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #109 : Май 21, 2012, 06:24:03 pm »
Массивы в 1С основаны на коллекциях, поэтому совсем не удивителен результат.
Не понял этого высказывания. Массив это коллекция везде, хоть в асме. А вот коллекция не обязательно массив.

Коллекция это же не структура данных, а назначение.
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Неархитектурная задачка
« Ответ #110 : Май 21, 2012, 07:45:37 pm »
Массивы в 1С основаны на коллекциях, поэтому совсем не удивителен результат.

Ну тык я выше написал, что и без массивов отношение примерно такое же.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #111 : Май 22, 2012, 01:04:37 am »
Выкладываю исходник. Стандартный C++, должен компилироваться везде, никаких завязок на платформу. Никаких низкоуровневых оптимизаций, максимум читабельности, но без излишних красивых абстракций.

Peter Almazov

  • Sr. Member
  • ****
  • Сообщений: 482
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #112 : Май 22, 2012, 04:33:53 am »
... максимум читабельности ...
Ужос.
С++ тошнотворен.
С трудом его читаю, поэтому можно было бы сказать, что сам виноват. Но я исхожу из того, что работа должна приносить удовольствие. Никакого удовольствия от ныряния в это дерьмо (C++) до сих пор не увидел.

По решению. Несмотря на трудности чтения C++ полагаю, что уловил суть. Как я понял, каждый очередной вариант создается копированием предыдущего и занимает место в памяти. Но в этом нет необходимости. Схема решения таких задач хорошо описана у Вирта. В случае неудачи после рекурсивного вызова игровое поле просто восстанавливается к исходному состоянию. В памяти размещено только одно игровое поле.
Именно так, по классике, и сделано у Сергея Губанова. Правда там все страшно затуманено unsafe'ностью. Но если восстановить то, что за этим стоит, то получится кристально чистое решение, как из учебника.

Тем не менее, vlad'у спасибо за то, что выложил решение. В нем есть определенная красота.
Я вот не стал решать – мысли были, но когда посмотрел решение Сергея, понял, что он уже сделал лучше.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #113 : Май 22, 2012, 03:15:04 pm »
Ужос.
С++ тошнотворен.

Мы еще не видели паскального решения ;)

С трудом его читаю, поэтому можно было бы сказать, что сам виноват. Но я исхожу из того, что работа должна приносить удовольствие. Никакого удовольствия от ныряния в это дерьмо (C++) до сих пор не увидел.

По решению. Несмотря на трудности чтения C++ полагаю, что уловил суть. Как я понял, каждый очередной вариант создается копированием предыдущего и занимает место в памяти.

Да. Хотя там копейки - в максимуме 9*9 = 81 вариант одновременно.

Но в этом нет необходимости. Схема решения таких задач хорошо описана у Вирта. В случае неудачи после рекурсивного вызова игровое поле просто восстанавливается к исходному состоянию.

Именно. Восстанавливается копированием оригинала на данном уровне рекурсии. Что не так? :)

В памяти размещено только одно игровое поле.

В данном случае бороться за одно поле нет смысла. Поле маленькое, копирование очень дешево. Аттачнул оптимизированный вариант. Копирование там точно такое же, оптимизирована только работа с битами (выкинул std::bitset). Работает на уровне последнего решения Сергея (0.04с на моей машине).

Именно так, по классике, и сделано у Сергея Губанова. Правда там все страшно затуманено unsafe'ностью. Но если восстановить то, что за этим стоит, то получится кристально чистое решение, как из учебника.

А кто сказал, что нельзя сделать лучше, чем в учебнике? :) Кстати, полное копирование поля в С++ выражается естественно и легко. В отличие от паскаля ;)

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #114 : Май 22, 2012, 03:18:20 pm »
Забыл аттачнуть.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #115 : Май 23, 2012, 03:28:46 pm »
И дабы не быть медленнее шарпа... :) Раскрутил циклы (с помощью шаблонов). ~0.03c плюс/минус погрешность измерения.

P.S. Вообще приятно, когда страшные рекурсивные шаблоны типа:
template<int N, int Inc>
bool
unroll( cell_t* cell, variant_t n )
    {
    return cell->exclude( n ) && unroll<N-1,Inc>( cell + Inc, n );
    }

разворачиваются в:
and DWORD PTR [eax+4], ecx
je SHORT $LN171@apply
and DWORD PTR [eax+8], ecx
je SHORT $LN171@apply
and DWORD PTR [eax+12], ecx
je SHORT $LN171@apply
        ...

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #116 : Май 24, 2012, 08:28:23 am »
Выкладываю свое решение. То, которое было сначала, ничего не менял, только код от комментированного логирования почистил.

MODULE P307Sudoku;

TYPE
Game* = RECORD
fixed-: BOOLEAN;
board-: ARRAY 9, 9 OF RECORD
fixed-: BOOLEAN;
val-: INTEGER; (* 0 = не заполнено *)
END;
possible: RECORD
hor, ver: ARRAY 9 OF SET;
areas: ARRAY 3, 3 OF SET
END
END;

PROCEDURE (VAR g: Game) Init*, NEW;
VAR i, j: INTEGER;
BEGIN
g.fixed := FALSE;
FOR i := 0 TO 8 DO
FOR j := 0 TO 8 DO
g.board[i, j].fixed := FALSE;
g.board[i, j].val := 0;
END
END;
FOR i := 0 TO 8 DO
g.possible.hor[i] := {1..9};
g.possible.ver[i] := {1..9};
END;
FOR i := 0 TO 2 DO
FOR j := 0 TO 2 DO
g.possible.areas[i, j] := {1..9}
END
END
END Init;

PROCEDURE (VAR g: Game) Fix*, NEW;
BEGIN
ASSERT(~g.fixed, 20);
g.fixed := TRUE
END Fix;

PROCEDURE (VAR g: Game) Possible* (col, row: INTEGER): SET, NEW;
VAR arC, arR: INTEGER;
BEGIN
arC := col DIV 3; arR := row DIV 3;
RETURN g.possible.hor[row] * g.possible.ver[col] * g.possible.areas[arC][arR]
END Possible;

PROCEDURE ^ TruncPoss (VAR g: Game; col, row, val: INTEGER);
PROCEDURE ^ ExtendPoss (VAR g: Game; col, row, val: INTEGER);

PROCEDURE (VAR g: Game) Set* (col, row, val: INTEGER), NEW;
BEGIN
ASSERT((1 <= val) & (val <= 9), 20);
ASSERT(g.board[col, row].val = 0, 21);
ASSERT(val IN g.Possible(col, row), 22);
g.board[col, row].val := val;
g.board[col, row].fixed := ~g.fixed;
TruncPoss(g, col, row, val)
END Set;

PROCEDURE (VAR g: Game) Reset* (col, row: INTEGER), NEW;
BEGIN
ASSERT(g.fixed, 20);
ASSERT(g.board[col, row].val # 0, 21);
ASSERT(~g.board[col, row].fixed, 22);
ExtendPoss(g, col, row, g.board[col, row].val);
g.board[col, row].val := 0
END Reset;

PROCEDURE TruncPoss (VAR g: Game; col, row, val: INTEGER);
VAR arC, arR: INTEGER;
BEGIN
arC := col DIV 3; arR := row DIV 3;
EXCL(g.possible.ver[col], val);
EXCL(g.possible.hor[row], val);
EXCL(g.possible.areas[arC, arR], val)
END TruncPoss;

PROCEDURE ExtendPoss (VAR g: Game; col, row, val: INTEGER);
VAR arC, arR: INTEGER;
BEGIN
arC := col DIV 3; arR := row DIV 3;
INCL(g.possible.ver[col], val);
INCL(g.possible.hor[row], val);
INCL(g.possible.areas[arC, arR], val)
END ExtendPoss;

END P307Sudoku.

MODULE P307SudokuAI;
IMPORT Sud := P307Sudoku, Services;

PROCEDURE Solve* (VAR g: Sud.Game; OUT solved: BOOLEAN);
VAR cell, col, row, val: INTEGER;

PROCEDURE SearchForw;
BEGIN
row := cell DIV 9; col := cell MOD 9;
WHILE (cell < 81) & ~(g.board[col, row].val = 0) DO
INC(cell);
row := cell DIV 9; col := cell MOD 9
END
END SearchForw;

PROCEDURE SearchBack;
BEGIN
row := cell DIV 9; col := cell MOD 9;
WHILE (cell > 0) & g.board[col, row].fixed DO
DEC(cell);
row := cell DIV 9; col := cell MOD 9
END
END SearchBack;

PROCEDURE Val (from: INTEGER; poss: SET): INTEGER;
BEGIN
INCL(poss, 10);
WHILE ~(from IN poss) DO
INC(from)
END;
RETURN from
END Val;

BEGIN
cell := 0;
SearchForw;
WHILE (0 <= cell) & (cell < 81) DO
val := Val(g.board[col, row].val+1, g.Possible(col, row));
IF g.board[col, row].val # 0 THEN
g.Reset(col, row)
END;
IF val < 10 THEN
g.Set(col, row, val);
INC(cell);
SearchForw
ELSE
DEC(cell);
SearchBack
END;
END;
solved := cell = 81
END Solve;

END P307SudokuAI.

MODULE P307SudokuCmds;
IMPORT Sud := P307Sudoku, AI := P307SudokuAI,  Log := StdLog,  In := i21sysIn;

VAR
game: Sud.Game;

PROCEDURE Load*;
VAR i, j, val: INTEGER;
BEGIN
game.Init;
In.Open;
FOR j := 0 TO 8 DO
FOR i := 0 TO 8 DO
In.Int(val);
ASSERT(In.done, 20);
ASSERT((0 <= val) &  (val <= 9), 21);
IF val # 0 THEN
game.Set(i, j, val)
END
END
END;
game.Fix
END Load;

PROCEDURE Solve*;
VAR solved: BOOLEAN;
BEGIN
AI.Solve(game, solved)
END Solve;

PROCEDURE Show*;
VAR i, j: INTEGER;
BEGIN
Log.Ln;
FOR j := 0 TO 8 DO
FOR i := 0 TO 8 DO
Log.Int(game.board[i, j].val)
END;
Log.Ln
END;
Log.Ln
END Show;

END P307SudokuCmds.

Губанов Сергей Юрьевич

  • Hero Member
  • *****
  • Сообщений: 590
    • Просмотр профиля
    • Домашняя страница
Re: Неархитектурная задачка
« Ответ #117 : Май 24, 2012, 09:11:56 am »
Выкладываю свое решение.
Без рекурсии, прикольно.

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #118 : Май 24, 2012, 09:35:01 am »
Выкладываю свое решение. То, которое было сначала, ничего не менял, только код от комментированного логирования почистил.
А из каких соображений выбрано такое название модуля - P307Sudoku? Sudoku - понимаю, а вот P307 не понимаю :-)
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Неархитектурная задачка
« Ответ #119 : Май 24, 2012, 12:20:01 pm »
Я его кинул в подсистему учебных материалов по группе П-307, так мне было удобно :)