{ -------------------------------------------------------- В этом модуле размещен объект GameField, отвечающий за расстановку кораблей человека и компьютера. Процедура DrawField виртуальная т.к. она различна для производных этого объекта и будет переопределена. В игре компьютер сам расставляет корабли как для себя так и для нас. И делает это таким образом: - находим свободную ячейку - выбираем направление расположения корабля (вправо или вниз) - проверяем, можем ли мы поставить туда этот корабль - если да то ставим его и помечаем все соседние клетки как занятые (BusyCell) - ну а если нет, то пробуем другие координаты Все игровое поле представляет из себя клетки с разными значениями. При своем ходе компьютер находит случайным образом незанятую ячейку (FreeCell) и "стреляет" туда. Если ход результативный, то она получает код "подбитый корабль" (Hit + размер корабля), в противном случае она помечается как промазанная (PastMove) и ход переходит к человеку. Обозначения на поле человека аналогичные. Компьютер не предпринимает попыток "добить" корабль в который однажды попал, как это делает любой человек. Подобная возможность не реализована из-за того, что главной целью была цель учебная, а не стратегическая. -------------------------------------------------------- Copyright(c) 1997 by Jassinskaja Jana, Jelena Kuznetsova -------------------------------------------------------- } Unit SeaField; interface const FieldSize = 9; { размер игрового поля } FreeCell = 0; { свободная ячейка } Ship1 = 1; { первый корабль } Ship2 = 2; { второй корабль} Ship3 = 3; { третий } Ship4 = 4; { четвертый } BusyCell = 50; { уже занятая ячейка (нет корабля, но правила не позволяют ставить корабль) } PastMove = 100; { промазанный ход } Hit = 200; { подбитый корабль + номер корабля } NotAvail = 150; { возвращается в случай выхода за границу поля } type { игровое пространство } GameSpace = array[0..FieldSize, 0..FieldSize] of byte; Direction = (RightDir, DownDir); { допустимые направления } PosVal = 0..FieldSize; { допустимые координаты поля } GameFieldPtr = ^GameField; GameField = object Xcoor, Ycoor : integer; { координаты игрового поля } WorkSpace : GameSpace; { игровое поле=пространство} constructor Init(InitX, InitY : integer); destructor Done; function GetCell(Ox, Oy : integer) : byte; { получить инфо из клетки } procedure SetCell(Ox, Oy : integer; Val : byte); { проставить в клетке инфо } procedure PutOnePart(Ox, Oy : PosVal; Val : byte); { установить часть корабля } function IsAvailable(Ox, Oy : PosVal) : boolean; { доступна ли ячейка для корабля } { поставить корабль на поле } function PutNewShip(Ox, Oy : PosVal; ShipSize : byte; dir : Direction) : boolean; procedure SetUpField; { создать поле с установленными кораблями } procedure DrawField; virtual; { вывести на экран игровое поле } end; HumanFieldPtr = ^HumanField; HumanField = object(GameField) procedure DrawField; virtual; end; ComputerFieldPtr = ^ComputerField; ComputerField = object(GameField) procedure DrawField; virtual; end; implementation uses Crt; (******************************************************************) (* GAMEFIELD *) (******************************************************************) constructor GameField.Init; begin Xcoor := InitX; Ycoor := InitY; FillChar(WorkSpace, SizeOf(WorkSpace), FreeCell); end; destructor GameField.Done; begin end; { получить значение из заданной ячейки } function GameField.GetCell; begin { проверка на допустимость значения } if (Ox < 0) or (Ox > FieldSize) or (Oy < 0) or (Oy > FieldSize) then GetCell := NotAvail else GetCell := WorkSpace[Ox, Oy]; end; { установить статус заданной ячейки } procedure GameField.SetCell; begin { проверка на допустимость значения } if (Ox >= 0) and (Ox <= FieldSize) and (Oy >= 0) and (Oy <= FieldSize) then WorkSpace[Ox, Oy] := Val; end; procedure GameField.PutOnePart; begin { ставим часть корабля и соседний клетки помечаем как занятые } WorkSpace[Ox, Oy] := Val; if GetCell(Ox-1, Oy-1) <> PastMove then SetCell(Ox-1, Oy-1, BusyCell); if GetCell(Ox+1, Oy-1) <> PastMove then SetCell(Ox+1, Oy-1, BusyCell); if GetCell(Ox-1, Oy+1) <> PastMove then SetCell(Ox-1, Oy+1, BusyCell); if GetCell(Ox+1, Oy+1) <> PastMove then SetCell(Ox+1, Oy+1, BusyCell); end; function GameField.IsAvailable; { проверяем доступность клетки для установки корабля (по периметру кораблика) } var i, j : integer; begin IsAvailable := TRUE; for i := 0 to 2 do for j := 0 to 2 do { если хоть одна занята, то не годится } if GetCell(Ox-1+i, Oy-1+j) in [Ship1, Ship2, Ship3, Ship4] then IsAvailable := FALSE; end; function GameField.PutNewShip; { устанавливаем корабль Возвращает TRUE, если удалось поставить корабль } var ix, iy : integer; { временные переменный с координатами кораблика } i : integer; { счетчик } flag : boolean; { указывает на возможность установки корабля } begin ix := 0; iy := 0; flag := TRUE; { проверяем, лезет ли корабль на поле при этой раскладке } case dir of RightDir : if (Ox + ShipSize > FieldSize+1) then flag := FALSE; DownDir : if (Oy + ShipSize > FieldSize+1) then flag := FALSE; end; { проверяем не заняты ли нужные ячейки } if flag and IsAvailable(Ox, Oy) then begin for i := 1 to ShipSize-1 do begin { при движении вправо увеличиваем ix } if dir = RightDir then Inc(ix) { а если вниз - iy } else Inc(iy); { можно ли поставить корабль? } if not IsAvailable(Ox+ix, Oy+iy) then flag := FALSE; end; { for } end else flag := FALSE; { расставляем корабль } if flag then begin case dir of RightDir : for i := 0 to ShipSize-1 do SetCell(Ox + i, Oy, ShipSize); DownDir : for i := 0 to ShipSize-1 do SetCell(Ox, Oy + i, ShipSize); end; end; PutNewShip := flag; end; procedure GameField.SetUpField; { готовим поле сражения } var rx, ry : integer; { случайно выбираемые координаты для корабля } d : Direction; { направление расположения корабля } i, j : byte; { счетчики: i - размер корабля; j - кол-во кораблей } begin for i := 4 downto 1 do for j := 4 downto i do { повторять до тех пор пока не удастся поставить корабль } repeat rx := Random(FieldSize+1); ry := Random(FieldSize+1); d := Direction(random(2)); until PutNewShip(rx, ry, i, d); end; procedure GameField.DrawField; begin end; (*******************************************************************) (* HumanField *) (*******************************************************************) { выводим на экран игровое поле игрока } procedure HumanField.DrawField; var i, j : integer; begin { устанавливаем окно для вывода поля } Window(Xcoor, Ycoor, Xcoor + FieldSize * 2 + 3, Ycoor + FieldSize + 2); GotoXY(3, 1); { выводим ряд координаты X } for i := 0 to FieldSize do Write(i:2); { рисуем координаты Y и корабли на нашем поле } for i := 0 to FieldSize do begin GotoXY(1, 2 + i); Write(i, ' '); for j := 0 to FieldSize do begin case WorkSpace[j, i] of FreeCell : Write('.'); Ship1 : Write('1'); Ship2 : Write('2'); Ship3 : Write('3'); Ship4 : Write('4'); PastMove : Write('*'); Hit..255 : Write('X'); BusyCell : write('.'); end; Write(' '); end; end; Window(1, 1, 80, 25); { восстанавливаем полный размер окна } end; (*******************************************************************) (* ComputerField *) (*******************************************************************) { выводим на экран игровое поля компьютера } procedure ComputerField.DrawField; var i, j : integer; begin Window(Xcoor, Ycoor, Xcoor + FieldSize * 2 + 3, Ycoor + FieldSize + 2); GotoXY(3, 1); for i := 0 to FieldSize do Write(i:2); for i := 0 to FieldSize do begin GotoXY(1, 2 + i); Write(i, ' '); for j := 0 to FieldSize do begin { понятное дело все корабли скрыты от наших глаз } case WorkSpace[j, i] of FreeCell, BusyCell : Write('.'); Ship1, Ship2, Ship3, Ship4 : Write('.'); PastMove : Write('*'); Hit..255 : Write(WorkSpace[j, i]-Hit); end; Write(' '); end; end; Window(1, 1, 80, 25); end; end.