Главная » Уроки по ООП » Урок 12. Работа с таблицами

Урок 12. Работа с таблицами

Дополнительные задания:

Игра «Жизнь». Идея игры состоит в том, чтобы, начав с какого-нибудь простого расположения фишек (организмов), расставленных по различным клеткам доски, про­следить за эволюцией исходной позиции под действием «гене­тических законов» Конуэя, которые управляют рождением, ги­белью и выживанием фишек.
Генетические законы игры сводятся к следующему.
Выживание. Каждая фишка, у которой имеются две или три соседние фишки, выживает и переходит в следующее поколение.
Гибель. Каждая фишка, у которой оказывается больше трех соседей, погибает, т. е. снимается с доски, из-за пере­населенности. Каждая фишка, вокруг которой свободны все соседние клетки или же занята только одна клетка, погибает от одиночества.

○ Рождение. Если число фишек, с которыми граничит ка­кая-нибудь пустая клетка, в точности равно трем (не боль­ше и не меньше), то на этой клетке происходит рождение нового «организма», т. е. следующим ходом на нее ставит­ся одна фишка.
Таким образом, гибель и рождение всех «организмов» про­исходят одновременно. Вместе взятые, они образуют одно поко­ление или один «ход» в эволюции начальной конфигурации. Ходы Конуэй рекомендует делать следующим образом:
1)  начать с конфигурации, целиком состоящей из черных фишек;
определить, какие фишки должны погибнуть, и положить на каждую из обреченных фишек по одной черной фишке;
найти все свободные клетки, на которых должны прои­зойти акты рождения, и на каждую из них поставить по одной фишке белого цвета;
выполнив все эти указания, еще раз внимательно прове­рить, не сделано ли каких-либо ошибок, затем снять с доски все погибшие фишки (т. е. столбики из двух фишек), а всех но­ворожденных (белые фишки) заменить черными фишками.
Пусть в нашей игре фишки n-го поколения будут умирать не сразу, а лишь после появления (п+2)-го поколения. Фишки разных поколений будут отличаться друг от друга цветом.
Решение
Положите на форму компонент ToolBar (панель инструмен­тов) со страницы Win32. Измените его свойство следующим об­разом:
EdgeBorders | [ebTop.ebBottom]
Сейчас панель инструментов будет находиться в самом верху формы, а ее верхняя и нижняя стороны будут выделены вдав­ленной линией.
Разместите на панели инструментов 5 кнопок. Для этого щелкните правой кнопкой мыши на панели инструментов и в появившемся контекстном меню выберите пункт NewButton. На панели инструментов появится кнопка типа TToolButton. С помощью этой кнопки мы будем задавать произвольную перво­начальную конфигурацию расположения фишек, поэтому назо­вите ее RandomTBt.
Добавьте еще одну кнопку и назовите ее NewTBt. Эта кноп­ка понадобится для очистки игрового поля.
Поместите разделитель на панель инструментов. Для этого опять вызовите контекстное меню панели инструментов и вы­берите в нем пункт NewSeparator.
Поместите еще одну кнопку на ToolBarl (ее свойство Name сделайте равным FadeTBt), разделитель и еще две кнопки типа TToolButton (с именами соответственно RunTBt и StopTBt). С помощью этих кнопок мы будем управлять ходом игры. Кноп­ка FadeTBt будет регулировать отображение трех или одного поколения фишек. Кнопки RunTBt и StopTBt предназначены для начала и остановки игры.
Для того чтобы поместить изображения на кнопки, нам по­надобится компонент ImageList со страницы Win32. Этот ком­понент может содержать серию изображений.

Создадим изображение для кнопки RandomTBt. Воспользу­емся программой ImageEditor, входящей в состав Delphi.
D Запустите ImageEditor, выполнив команду Пуск/Програм-мы/Borland Delphi 5/Image Editor.
Для создания пиктограммы выберите в пункте меню File команду New Bitmap File (.bmp). В диалоговом окне Bitmap Properties задайте размеры изображения (Height и Width) равными 20.
С помощью инструментов программы Image Editor создай­те изображение для кнопки RandomTBt.
Сохраните в папке Life под названием Bitmapl.bmp.
Задание для самостоятельного выполнения. Создайте изображение для кнопки NewTBt и сохраните его под именем Bitmap2.bmp.
Для остальных кнопок воспользуемся стандартным набором изображений Delphi.
Поместите изображения, предназначенные для кнопок при­ложения, в компонент ImageListl.
Щелкните правой кнопкой мыши на этом компоненте и в контекстном меню выберите пункт ImageList Editor...
В  диалоговом  окне  редактора изображений  LifeFrm. Image I List ImageList щелкните на кнопке Add.
В диалоговом окне открытия файла выберите файл Bit­ mapl.bmp с изображением для кнопки RandomTBt. В ре­дакторе изображений появится выбранное изображение под индексом 0. Аналогичным образом добавьте изобра­ жение для кнопки NewTBt (оно должно иметь индекс 1).
Изображения для трех остальных кнопок выберите в папке С:/Program Files/Common Files/Borland Shared/Images/Buttons.
В диалоговом  окне  редактора  изображений  LifeFrm. Image I List ImageList щелкните на кнопке Add, выберите файл С:/ Program Files/ Common Files/ Borland Shared/ Images/ Buttons/ Day.bmp. После щелчка на кнопке Open появится окно (рис. 6.2.2) с сообщением о том, что размер изображения в day.bmp больше, чем размер, определен­ный в ImageList. Нужно разделить на 2 обособленных изображения? Щелкните на кнопке No.
Установите Options диалогового окна редактора изображе­ ний в значение Crop — срезать.

 

Добавьте изображения для кнопок FadeTBt (индекс равен двум), RunTBt (индекс равен трем) и StopTBt (индекс равен че­тырем).

Чтобы показать изображения на кнопках, установите свой­ство Images компонента ToolBarl в ImagelListl, а у каждой кнопки свойству Imagelndex присвойте индекс соответствую­щего изображения в редакторе изображений (для кнопки RandomTBt — 0, для NewTBt — 1 и т. д.).
Эксперимент. Сохраните проект. Запустите, на панели инст­рументов должны появиться кнопки с созданными вами изобра­жениями . ♦
Для изображения жизни организмов нам понадобится ком­понент StringGrid. Установите его свойства следующим обра­зом:

Align

alClient

ColCount

50

DefaultColWidth

10

DefaultRowHeight

10

FixedCols

0

FixedRows

0

Name

LifeSGd

RowCount

25

Измените размеры формы так, чтобы у компонента LifeSGd не было полос прокрутки.
Смену поколений организмов будем отображать через каж­дую секунду. Воспользуемся компонентом Timer (страница System).
Класс TTimer поддерживает единственный обработчик собы­тия OnTimer. Это событие появляется через интервал времени, заданный свойством Interval. Таким образом, если свойство Interval установлено в 1000 (миллисекунд), то обработчик со­бытия OnTimer будет вызываться каждую секунду.
В классе TTimer определено свойство Enabled, значение Fal­se которого приводит к игнорированию событий OnTimer, зна­чение True позволяет обрабатывать события OnTimer.
Компонент Timer — это невизуальный компонент Delphi, т. е. отображается он только на этапе проектирования прило­жения. Положите компонент Timer на форму, установите зна­чения свойств следующим образом:

Итак, визуальное проектирование приложения завершено. Сохраните проект.
2-й этап. Написание программного кода
Опишем глобальные переменные.
В разделе Const раздела Interface опишите две глобальные константы
MX = 50;                             {количество столбцов в LifeSGd}
MY = 25;                              {количество строк в LifeSGd}
В разделе Private класса LifeSGd опишите глобальную пере­менную
Fade: Boolean;
Эта переменная будет отвечать за количество поколений, отображаемых приложением: если значение Fade равно True — будут отображаться три поколения организмов (фи­шек), иначе — только живые организмы (фишки), т. е. одно поколение.
Воспользуемся свойством Cells компонента LifeSGd для хра­нения состояния организмов колонии. Введем следующие обо­значения:
— фишка мертва;
— фишка жива;
— фишка мертва одно поколение (на предыдущем ходе она была жива);
— фишка мертва два поколения.
Как уже говорилось, генерация каждого нового поколения будет происходить по таймеру, поэтому при создании формы необходимо таймер выключить. Кроме того, пусть в самом на­чале переменная Fade будет равна False, а все организмы будут помечены мертвыми. В соответствии с этими утверждениями обработчик события создания формы будет выглядеть так:
procedure  TLifeFrm.FormCreate(Sender:  TObject);
var i,j:Integer;
begin
Timerl.Enabled  := False;
Fade  := False;
for i  :=0  to MX-1 
do for j  :=0  to МУ-1  do LifeSGd.Cells [i,j]   :=  '0';
end;
Рассмотрим процедуру задания произвольной расстановки фишек — событие OnClick кнопки RandomTBt.
procedure TLifeFrm.RandomTBtClick(Sender: TObject);
var x,у: Integer; begin
Randomize;        {включаем генератор случайных чисел}
for у :=0 to MY-1 do for x :=0 to MX-1 do LifeSGd.Cells[x,y]:=IntToStr(Random(2));
{если в ячейку записывается единица, то фишка жива, если в ячейку записывается нуль, то фишка считается мертвой} end;
Кнопка NewTBt используется для очистки содержимого ячеек компонента LifeSGd. Поэтому в обработчике события OnClick данной кнопки нужно просто значению каждой ячейки присвоить нуль. Кроме того, надо выключить таймер. Обработ­чик события будет выглядеть так:
procedure TLifeFrm.NewTBtClick (Sender: TObject);
var y,x: Integer; begin
for у := 0 to MY-1 do for x := 0 to MX-1 do LifeSGd. Cells [x, y]   := '0';
Timerl.Enabled := False; end;
При нажатии кнопки FadeTBt будем изменять значение пе­ременной Fade, которая показывает, изображать или нет несколь­ко поколений. Если Fade равно True, то кнопка будет вдавлен­ной. Создайте следующий обработчик события:
procedure TLifeFrm.FadeTBtClick(Sender: TObject);
begin
Fade := not(Fade);
FadeTBt.Down := Fade; end;
Для запуска игры служит кнопка RunTBt. При ее нажатии таймер должен начинать работать, кнопка RunTBt — станови­ться вдавленной, а кнопка StopTBt — принимать обычный вид. Все эти действия выполняются в данном обработчике:
procedure TLifeFrm.RunTBtClick(Sender: TObject); begin
Timerl.Enabled := True;
RunTBt.Down := True;
StopTBt.Down := False; end;
Кнопка StopTBt используется для остановки работы про­граммы. Обработчик события OnClick этой кнопки должен вы­глядеть так:
procedure TLifeFrm.StopTBtClick (Sender: TObject); begin
Timerl.Enabled := False; StopTBt.Down := True; RunTBt.Down := Falser-end;
Эксперимент. Сохраните проект. Убедитесь в правильности функционирования написанного кода. ♦
Задавать расположение фишек можно и вручную. Для этого достаточно щелкнуть левой кнопкой мыши по нужной вам ячей­ке. Запрограммируем такой вариант расстановки фишек. Удоб­нее всего помечать фишки как живые в событии OnSelectCell компонента LifeSGd:
procedure TLifeFrm.LifeSGdSelectCell(Sender: TObject;
ACol, ARow: Integer; var CanSelect: Boolean);
begin
if LifeSGd.Cells[Acol,  Arow]='l' then LifeSGd.Cells[Acol,  Arow]:=  '0'
else LifeSGd.Cells [Acol,  Arow]:=  4'; end;
Остановимся подробнее на том, как изменяется цвет каждой ячейки. Известно, что прорисовка ячеек происходит в событии OnDrawCell. Это событие происходит столько раз, сколько ячеек содержит компонент StringGrid (в задаче — LifeSGd). Кроме того, событие вызывается каждый раз при изменении значения свойства Cells. Именно поэтому не приходилось вручную пере­рисовывать LifeSGd.
Схема изменения цвета ячейки достаточно проста: обработ­чик данного события проверяет значение свойства Cells ячейки (ACol, ARow) и в зависимости от него присваивает нужный цвет кисти свойства Canvas компонента LifeSGd. Живые фиш­ки изображаются синим цветом; предыдущее поколение (фиш­ки, мертвые в течение одного хода) — светло-голубым цветом; фишки, мертвые в течение двух ходов, — светло-фиолетовым цветом; мертвые фишки — белым цветом. Однако если значе­ние переменной Fade равно False, то отображаются только жи­вые и мертвые клетки (без промежуточных состояний). После того как цвет установлен, остается только заполнить этим цве­том нужную ячейку с помощью метода FillRect свойства Canvas. В результате процедура будет выглядеть следующим образом:
procedure TLifeFrm.LifeSGdDrawCell{Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
LifeSGd.Canvas.Brush.Color := clWhite;
case StrToInt(LifeSGD.Cells [ACol, ARow])of 1: LifeSGd.Canvas.Brush.Color := clBlue;
2: if Fade then LifeSGd.Canvas.Brush.Color := clBlue - 13000; 3: if Fade
then LifeSGd.Canvas.Brush.Color := clBlue-17000; end;
LifeSGd.Canvas.FillRect(Rect);
end;
Эксперимент. Запустите проект, обратите внимание, что после щелчков мышью по полю таблицы клетки перекрашива­ются. ♦
Итак, осталось написать последнюю процедуру, в которой будем определять, какие фишки выживут, а какие умрут. Имен­но здесь нам и понадобится таймер. На каждый «тик» таймера будет вызываться процедура OneStep, в которой оценивается текущее состояние фишек, и в зависимости от него строится но­вое расположение фишек. Добавьте название процедуры OneStep в раздел public описания класса формы TLifeFrm.

Public
procedure OneStep;

Принцип выбора живых фишек следующий: просматриваем поочередно все ячейки; для каждой ячейки считаем количество окружающих ее живых фишек; в зависимости от количества этих фишек заполняем элементы двумерного массива А либо нулем, либо единицей; далее просматриваем элементы этого массива Айв зависимости от их значений изменяем свойство Cells компонента LifeSGd.
Для реализации этого принципа нам понадобится двумер­ный массив А, элементы которого соответствуют ячейкам ком­понента LifeSGd. Размерность массива А будет аналогична раз­мерности LifeSGd. Кроме того, нам будут нужны два массива— константы DX и DY, содержащие приращение по вертикали и горизонтали соответственно. Эти массивы понадобятся для про­смотра соседних с клеткой ячеек.
procedure TLifeFrm.OneStep; const
DX : array [1..8] of Integer = (-1, 0, 1,  1, 1, 0,-1,-1); DY : array [1..8] of Integer = (-1,-1,-1, 0, 1, 1, 1, 0) ; var
i, j, k, Count: Integer; A: array [0..MX, 0..MY] of Byte; begin
Fill Char {A, SizeOf (A) , 0) ;             {обнуляем значения массива А}
for i:=l to MX-1 do       {просматриваем все ячейки}
for j:=1 to MY-1 do begin Count:=0;
{переменная Count используется для подсчета количества живых фишек}
for k:=l to 8 do
{просматриваем все ячейки, которые являются соседними для ячейки (i, j)}
if LifeSGd.Cells[i+DX[k],j+DY[k]]='1' then Inc(Count); case Count of
{анализируем полученное значение переменной Count и в зависимости от него заполняем массив А}
0..1,4..8: A[i,j]:=0; 2: if LifeSGd.Cells[i,j]=•1' then A[i,j]:=1
else A[i,j]:=0; 3: A[i,j]:=1;
end; end;
for i:=0 to MX-1 do
{меняем значения ячеек компонента LifeSGd}
for j:=0 to MY-1 do
if A[i,j]=l then LifeSGd.Cells[i,j] : = 'l•
{помечаем фишку как живую}
else if (LifeSGd.Cells[i,j] = ' 1' ) then LifeSGd.Cells [i,j] : = '2r
{помечаем фишку как мертвую в течение одного поколения}
else if (LifeSGd.Cells[i,j]='2l) then LifeSGd.Cells[i,j]:='3'
{помечаем фишку как мертвую в течение двух поколений}
else LifeSGd.Cells[i,j]:='0';
{помечаем фишку как окончательно мертвую}
end;
Эксперимент. Мы завершили создание приложения. Сохра­ните проект.
Запустите приложение. Проследите за изменением популя­ции клеток.
Популяция непрестанно претерпевает необычные, нередко очень красивые и всегда неожиданные изменения. Иногда пер­воначальная колония организмов постепенно вымирает, т. е. все фишки исчезают, однако произойти это может не сразу, а лишь после того, как сменится очень много поколений. Однако в большинстве своем исходные конфигурации либо переходят в устойчивые (последние Конуэй называет «любителями спокой­ной жизни») и перестают изменяться, либо навсегда переходят в колебательный режим.
Придумайте колебательные и устойчивые конфигурации по­пуляции. ♦
Задания для самостоятельного выполнения
6.1. Приложение «Секундомер» (рис. 6.2.3). При нажатии на кнопку «Пуск» запускается секундомер (минуты : секун­ды : десятые доли секунды), а название кнопки изменяется на «Пауза». При нажатии на кнопку «Пауза» отсчет времени прекращается, а название кнопки изменяется на «Пуск». При нажатии на кнопку «Стоп» секундомер останавливает­ся и происходит сброс времени.

 

6.2.         Напишите программу, которая с помощью компонентов Gau­ge (страница Samples) отображает количество часов, минут, секунд, прошедших с начала суток.
Примечание. Воспользуйтесь функциями Time (возвращает теку­щее время) и TimeToStr(flaTa) (преобразует полученную дату в строко­вый формат).
«Часы шахматиста». Принцип работы: в начале шахматной партии часы установлены в нулевое положение. В начале игры часы первого шахматиста стартуют, по окончании хода он нажимает на кнопку, в результате чего его часы останав­ливаются и стартуют часы второго, после хода второго иг­рока его часы останавливаются, часы первого игрока про­должают отсчет от установленного ранее времени и т. д.
Приложение «Крестики-нолики». Дано: доска (поле) раз­мерам 3x3. Напоминаем суть игры. Партнеры по очереди ставят на поля квадрата (доски) крестики и нолики, выиг­рывает тот, кто первым выстроит три своих знака в ряд. Игра длится не более девяти ходов. Если никому из игро­ков не удается добиться цели, партия заканчивается вни­чью. Напишите приложение, в которой партнерами высту­ пают компьютер и человек.
Примечание. Для изображения крестиков и ноликов воспользуй­тесь компонентом ImageList. Поместите в этот компонент изображе­ния. Обработчик события OnDrawCell компонента StringGrid будет со­держать следующий код:
Number := StrToInt(StringGridl[ACol, ARow]);
{В ячейках StringGrid помещены символы 0 (клетка свободна), 1 (крестик), 2 (нолик)}
ImageListl.Draw{StringGridl.Canvas,Rect.Left-2,Rect.Top-2, Number) ;
{в ячейке StringGridl отображается изображение под номером Number}

6.5.         Создайте приложение «Пятнадцать». Приложение произволь­ным образом расставляет фишки (1... 14) в коробке, оставляя свободной клетку в правом нижнем углу. В строке состояния должно отображаться количество сделанных ходов.
После завершения игры должно выводиться сообщение, по­здравляющее с выигрышем.
Создайте форму, запрашивающую имя победителя. Сохра­ните имя победителя и его результат в файле. Предусмот­рите просмотр победителей игры.
На форме должно отображаться количество минут и секунд, прошедших с начала игры.

Приложение «Перевертыши». Дано поле размером 4x4 (6x6, 8x8). В каждой клетке расположены фишки — синие и белые. Начальное расположение фишек генерируется слу­чайным образом. За один ход можно перевернуть фишку в какой-либо произвольно выбранной ячейке, одновременно с ней переворачиваются фишки в соответствующих ячейках по вертикали и горизонтали. Цель игры: получить во всех ячейках фишки одного и того же цвета.
Приложение «Волки и овцы». В данную игру можно играть с кем-нибудь вдвоем или с самим собой. Один играет за овец, другой — за волков. У вас есть квадратная «поляна» разме­ром 4x4 (рис. 6.2.4). В ее углах стоят 2 овцы («О») и 2 волка («В»).

Ходы осуществляются по очереди: волк, овца, волк и т. д. При этом каждый может передвигаться только на соседнюю клетку вперед, назад, влево и вправо (рис. 6.2.5). Но если овца окажется на какой-нибудь соседней клетке по диагонали, то волк очередным ходом может съесть ее. В этом случае он становится на клетку, где была овца, а та уходит с поляны. Если зазевается волк, овца делает то же самое. Выигрывает тот, кто останется на поляне.
Приложение «Ку-ну» (корейская игра). Играют два челове­ка. На поле размером 5x5, клетки которого являются ка­мушками, стоят два отряда воинов по 7 человек в каждой (рис. 6.2.7). Одни воины одеты в синее кимоно, другие — в зеленое. После того как брошен жребий, какому отряду на­чать игру, любой из воинов прыгает на соседний камушек, но только по диагонали. Затем точно так же прыгает воин из другого отряда. Оставаться всему отряду на месте никак нельзя, так как на скользких камнях трудно держать рав­новесие, поэтому если камушки впереди уже заняты, тогда придется прыгать назад — опять же по диагонали — на сво­бодное место. Побеждает тот, кто быстрее успеет перейти на другой берег.


6.9. Приложение «Вечный Календарь». Напишите приложение, визуальный интерфейс которого показан на рис. 6.2.8.
Примечание.  Воспользуйтесь компонентом Calendar (страница Samples).


При изменении выбранной даты отобразите соответствую­щие данные в заголовок формы.
Примечание. Для получения информации о компоненте восполь­зуйтесь файлом c:\Program files\ Borland\ Delphi5\ Source\ Samples\ Calendar.pas
6.10. Модифицируйте приложение, описанное в задании 6.9. а) Известно, что астрологи делят год на 12 периодов и каждо­му из них ставят в соответствие один из знаков Зодиака:
20.01-18.02 Водолей              21.05-21.06 Близнецы       24.09-22.10 Весы
19.02-20.03 Рыбы                  22.06-22.07 Рак      23.10-22.11 Скорпион
21.03-19.04 Овен                  23.07-22.08 Лев      23.11-21.12 Стрелец
20.04-20.05 Телец                 23.08-23.09 Дева    22.12-19.01 Козерог
Модифицируйте программу так, чтобы свойство Hint ком­понента Calendar отображало знак Зодиака для выбранной даты.
Ь) В старояпонском календаре был принят 60-летний цикл, состоявший из пяти 12-летних подциклов. Подциклы обо­значались названиями цвета: зеленый, красный, желтый, белый и черный. Внутри каждого подцикла годы носили на­звания животных: крысы, коровы, тигра, зайца, дракона, змеи, лошади, овцы, обезьяны, курицы, собаки и свиньи (1984 год — год зеленой крысы — был началом очередного цикла). Модифицируйте программу так, чтобы свойство Hint формы отображало название выбранного года по старо­японскому календарю.
Приложение «Блоки». На поле размером 6x6 находятся картинки (по две одинаковые), невидимые для игрока. Необ­ходимо открыть все картинки. Картинки открываются по­парно, при этом, если открыты одинаковые картинки, они исчезают. Во время игры открытыми могут быть только две картинки: при открытии третьей картинки предыдущие две закрываются. Цель игры: открыть все картинки за наимень­шее число попыток.
«Биологические ритмы». Биологические ритмы вычисляют, основываясь на гипотезе, что существует три цикла: физи­ческий (его период равен 23 дням), эмоциональный (пери­од — 28 дней) и интеллектуальный (период — 33 дня). Кри­вые биологических ритмов могут быть представлены в виде синусоид. Начало всех трех кривых — день рождения. В пер­вой половине каждого периода значения синусоиды положи­тельны — это дни рабочего, приподнятого настроения, в дни второй части периода (когда значения синусоиды отрицате­льны) человек находится в пассивном, плохом настроении. В самом начале (после дня рождения) все биологические рит­мы попадают в отрицательную часть периода. Составьте про­грамму, которая запрашивает день рождения; число, на ко­торое следует определить значения синусоид биологического ритма, и по этим данным строит синусоиды на 1 месяц.
6.5. Приложение «Японский кроссворд». В клетках японского кроссворда скрываются не слова, а картинки. Задача — на­рисовать картинку по числам, которые проставлены слева от строк и над колонками. Числа разделены на группы, коли­чество которых показывает, сколько групп закрашенных клеток находится в соответсвующей линии а сами числа показывают, сколько слитных закрашенных клеток содер­жит каждая группа. Например, числа 2, 5 и 4 означают, что в этом ряду есть 3 группы, состоящие: первая — из 2, вторая — из 5, третья — из 4 закрашенных клеток. Группы разделены как минимум одной пустой клеткой. Пустые клетки могут быть и по краям рядов. Самое трудное — опре­делить, сколько же пустых клеток находится между закра­шенными группами.
Решение японского кроссворда разберем на простом примере. Если возле ряда стоит одно число, которое больше, чем по­ловина длины ряда, то несколько клеток в середине ряда бу­дут закрашены. Поэтому их можно смело помечать. В при­мере можно закрасить некоторые клетки в 1-й, 4-й и 5-й стро­ках (рис. 6.2.9). Шестая строка содержит одну группу из 10 клеток, поэтому всю эту строку можно сразу закрасить.

Теперь посмотрим на колонки. В первой всего одна клетка, ее положение уже известно, так что остальные клетки этой колонки явно пустые — отметим их серым цветом и не бу­дем обращать на них внимание. Со второй колонкой посту­пим аналогично. Можно еще закрасить несколько клеток в четвертой колонке, так как группа содержит 7 клеток, а вы­сота всей колонки 8, поэтому можем закрасить средние 6 к ле­ток (рис. 6.2.10).

Продвигаясь шаг за шагом, получим вот такой автомобиль (рис. 6.2.11).

Напишите приложение, которое помогает разгадывать японский кроссворд, т. е. получает на входе файл с задани­ем японского кроссворда, а затем при выборе (отмене выбо­ра) той или иной клетки отображает это в клетках справа и снизу.

 

Составитель: Салий Н.А.

Яндекс.Метрика
Сайт создан в системе uCoz