Re: Японские кроссворды

From
Andrew Perevodchik ()
To
Dmitry Petanin
Date
2003-01-14T23:42:31Z
Area
RU.ALGORITHMS
From: Andrew Perevodchik <ok@naverex.kiev.ua>

Привет!

 DP> А не встречали ли кто какой-нибудь теории или алгоритма по решению
 DP> сабжа, желательно PAS, но можно СPP, нужно для лабораторной ...

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

Это процедура решения одной строки (или столбца) в кроссворде. Если
выполнить несколько проходов по строкам и столбцам, классические
кроссворды (не "поисковые") решаются.

На входе имеем Descr -- массив целых чисел с указанием длин
закрашенных блоков, Have -- массив, представляющий клетки в
рассматриваемой строке (или столбце). Одна клетка -- один байт. Если
не известно, что там -- 0, если наверняка закрашена -- 1, если
наверняка не закрашена -- 2.

Работает так: перебирает все возможные расположения блоков при
заданной длине строки и Descr. Если рассматриваемая комбинация не
противоречит уже отмеченным клеткам, она побитно накладывается на
массив-результат, который изначально инициализируется троечками, по
правилу AND. В итоге получаем массив, представляющий строку, с
некоторыми "закрашенными" или "отминусованными" клетками.

Такое поэтапное решение использует человек, так что этим способом
можно проверять кроссворды на "решабельность".

----- Windows Clipboard -----

procedure Solve(Descr: array of Byte; var Have: array of Byte);
var
  Total, Len, Vary: Integer;
  I, J, K, N: Integer;
  Addons, Test, Final: array of Byte;
begin
  Total:=Length(descr);
  Len:=Length(have);
  Vary:=Len+1;
  for I:=0 to Total - 1 do
    Vary:=Vary-descr[I]-1;
  if Vary < 0 then begin
    raise Exception.Create('Invalid input data.');
    Exit;
  end;
  if Len <= 0 then begin
    raise Exception.Create('Invalid size of input data.');
    Exit;
  end;
  SetLength(Addons, Total);
  SetLength(Test, Len);
  SetLength(Final, Len);
  for I:=0 to Total - 1 do
    Addons[I]:=0;
  for I:=0 to Len - 1 do
    Final[I]:=3;
  I:=1;
  while I >= 0 do begin
    J:=0;
    for K:=0 to Total - 1 do begin
      for N:=Ord(K = 0) to Addons[K] do begin
        Test[J]:=1;
        Inc(J);
      end;
      for N:=1 to descr[K] do begin
        Test[J]:=2;
        Inc(J);
      end;
    end;
    while J < Len do begin
      Test[J]:=1;
      Inc(J);
    end;
    K:=0;
    for J:=0 to Len - 1 do
      if (Test[J] or Have[J]) = 3 then begin
        K:=1;
        Break;
      end;
    if K = 0 then
      for J:=0 to Len - 1 do
        Final[J]:=Final[J] and Test[J];
    I:=Total-1;
    while I >= 0 do begin
      Addons[I]:=Addons[I]+1;
      Dec(Vary);
      if Vary < 0 then begin
        Vary:=Vary+Addons[I];
        Addons[I]:=0;
        Dec(I);
      end
      else
        Break;
    end;
  end;
  if Final[0] = 3 then begin
    raise Exception.Create('Value doesn''t match numbers.');
    Exit;
  end;
  for J:=0 to Len - 1 do
    Have[J]:=Final[J];
end;

-----------------------------

Андрей Переводчик
--- ifmail v.2.15dev5
 * Origin: Navigator Online Internet News Server (2:5020/400)