Sei sulla pagina 1di 10

PROGRAM Pandemie;

USES
WinCrt,
PanGUI;
BEGIN
StartPandemie;
END.

UNIT PanGUI;
INTERFACE
(*---------------------------------------------------------------------------start the game
----------------------------------------------------------------------------*)
PROCEDURE StartPandemie;
(*---------------------------------------------------------------------------go to next line
----------------------------------------------------------------------------*)
PROCEDURE LineBreak;
IMPLEMENTATION
USES
WinCrt,
PanLogic;
(*---------------------------------------------------------------------------draw the column-header which goes from 1 to 8
----------------------------------------------------------------------------*)
PROCEDURE DrawColumnHeader;
VAR
i: BYTE;
BEGIN
Write(' ');
(* write 1 to 8 with minimum width of 4 *)
FOR i := Low(cities) TO High(cities) DO BEGIN
Write(i:4);
END;
END;
(*---------------------------------------------------------------------------go to next line
----------------------------------------------------------------------------*)
PROCEDURE LineBreak;
BEGIN
WriteLn('');
END;
(*---------------------------------------------------------------------------draw a line of board
----------------------------------------------------------------------------*)
PROCEDURE DrawLine;
VAR
i: INTEGER;
BEGIN
Write(' ');
FOR i := Low(cities) TO High(cities) DO BEGIN
Write('+---')
END;
WriteLn('+');
END;

(*---------------------------------------------------------------------------[IN]: currentRow ........ contains cities for current row


[IN]: currentRowIndex ... the row-index (1-8)
draw data-row which contains the row-caption, the pipe signs and the cities (1-8)
----------------------------------------------------------------------------*)
PROCEDURE DrawRow(currentRow: cities; currentRowIndex: MAP_INDEX);
VAR
i: BYTE;
BEGIN
Write(' ');
(* row-caption (1-8) *)
Write(currentRowIndex);
(* for each column of current row *)
FOR i := Low(cities) TO High(cities) DO BEGIN
(* Pipe-sign for vertical borderline *)
Write('|');
(* depending on health/infections-status write the adequate value/sign *)
CASE currentRow[i] OF
CIS_CERO: Write(' - ':3);
CIS_ONE:
Write(' 1 ');
CIS_TWO:
Write(' 2 ');
CIS_THREE: Write(' 3 ');
END;
END;
Write('|');
END;
(*---------------------------------------------------------------------------draw all lines and rows, using drawing-routines (0-0 to 8-8)
----------------------------------------------------------------------------*)
PROCEDURE DrawRows;
VAR
i: MAP_INDEX;
BEGIN
(* for each row of board *)
FOR i := Low(austria) TO High(austria) DO BEGIN
(* draw the line *)
DrawLine;
(* draw the content of datastructure for current row (blac, white, empty) *)
DrawRow(austria[i], i);
(* next line *)
LineBreak;
END;
(* draw the last line of board outside of loop *)
DrawLine;
END;
(*---------------------------------------------------------------------------[IN]: othelloBoard ..... the game-board.
=> has to be initializes minimum one time!
=> after made a move, this routine is called do re-draw the board on screen
----------------------------------------------------------------------------*)
PROCEDURE DisplayMap;
BEGIN
(* 1-8 *)
DrawColumnHeader;
LineBreak;
(* draw all rows (A1-H8) *)
DrawRows;
END;

(*---------------------------------------------------------------------------[IN/OUT]: othelloBoard .... the game-board which gets modified by valid moves
[IN]: moves ............... the temporary board
run the game until two invalid moves in a row. black begins the game.
after that the player switch each move. after a player inserted a move, validate
it, and if valid, place the stone and turn all turnable enemy stones.
----------------------------------------------------------------------------*)
PROCEDURE RunGame;
VAR
coordinate: STRING;
stopGame: BOOLEAN;
healOrInfect: CHAR;
row, column: MAP_INDEX;
ampules: INTEGER;
BEGIN
(* initialize count for ending the game *)
stopGame := FALSE;
(* the game takes until two invalid moves in a row *)
WHILE NOT stopGame DO BEGIN
(* clear the screen *)
ClrScr;
(* draw the board again *)
DisplayMap;
(* show message depending on stone color *)
Write('Heal ("H") or Infect ("I") - "S" = stop game: ');
ReadLn(healOrInfect);
healOrInfect := UpCase(healOrInfect);
(* S means stop the game *)
stopGame := healOrInfect = 'S';
IF NOT stopGame THEN BEGIN
Write('Enter the city coordinates: ');
ReadLn(coordinate);
coordinate[1] := UpCase(coordinate[1]);
(* split the coordinate into row and column. if worked, go ahead *)
IF SplitCoordinate(coordinate, row, column) THEN BEGIN
(* decide if infect or heal *)
IF healOrInfect = 'I' THEN BEGIN
InfectCity(row, column);
END
ELSE BEGIN
Write('Enter number of ampules: ');
ReadLn(ampules);
(* if city which has to be healed is NOT infected - do nothing *)
IF GetCityInfectionState(row, column) > CIS_CERO THEN BEGIN
(* save sender *)
SetSender(row, column);
HealCity(row, column, ampules);
END;
END;
END;
END;
END;
END;

PROCEDURE StartPandemie;
VAR
newGame: CHAR;
BEGIN
newGame := 'N';
WHILE UpCase(newGame) = 'N' DO BEGIN
ClrScr;
(* Initialize map for new game *)
InitializeMap;
(* run the game *)
RunGame;
(* linebreak *)
LineBreak;
Write('Drcke "N+ENTER" fr neues Spiel, oder eine andere Taste um zu beenden:');
ReadLn(newGame);
END;
END;
BEGIN
END.

UNIT panlogic;
INTERFACE
TYPE
(* type for max rows and columns*)
MAP_INDEX = 1..8;
(* ein Zeile hat 8 Spalten *)
cities = ARRAY[MAP_INDEX] OF BYTE;
(* Spielbrett mit Zeilen A-H und Spalten 1-8 *)
map = ARRAY[MAP_INDEX] of cities;
(*---------------------------------------------------------------------------initialize the incoming game-map and give it back
-> all cities are healthy
----------------------------------------------------------------------------*)
PROCEDURE InitializeMap;
(*---------------------------------------------------------------------------[IN] coordinate ... A coordinate (for example 12)
[IN/OUT] row ...... The row-part of coordinate (1-8)
[IN/OUT] column ... The column-part of coordinate (1-8)
[OUT] result ...... TRUE = converting to MAP_INDEX worked
split the incoming coordinate into a row part and a column part
f.e.: coordinate = 12 -> row = 1; column = 2;
----------------------------------------------------------------------------*)
FUNCTION SplitCoordinate(coordinate: STRING; VAR row, column: MAP_INDEX): BOOLEAN;
(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates
infect the city equal to incoming coordinates entered by user, and infect the
neighbours around (up, down, left, right) if InfectionIndex gets "CIS_THREE"
=> the routine is recursive, so chain-reaction is possible
----------------------------------------------------------------------------*)
PROCEDURE InfectCity(row, column: MAP_INDEX);
(*---------------------------------------------------------------------------[IN]: row, column ....... coordinates of city to heal
[IN]: ampules ........... number of available ampules
heal the city equal to incoming coordinates, and forward remaining ampules to
neighbour cities
----------------------------------------------------------------------------*)
PROCEDURE HealCity(row, column: MAP_INDEX; ampules: INTEGER);
(*---------------------------------------------------------------------------save the row and column before go into recursion
----------------------------------------------------------------------------*)
PROCEDURE SetSender(row, column: MAP_INDEX);
(*---------------------------------------------------------------------------[IN]: row, column ...... find cityInfectionState on incoming coordinates and
give back as result [OUT]
----------------------------------------------------------------------------*)
FUNCTION GetCityInfectionState(row, column: MAP_INDEX): BYTE;
VAR
(* austria is the map of cities *)
austria, austriaTmp: map;
(* to remember the sender in recursion (heal) *)
senderRow, senderColumn: MAP_INDEX;
CONST
(* CIS = CityInfectionState *)
CIS_CERO = 0;
CIS_ONE
= 1;
CIS_TWO
= 2;
CIS_THREE = 3;

IMPLEMENTATION
(*--------------------------------------------------------------------------*)
PROCEDURE InitializeMap;
VAR
i, k: BYTE;
BEGIN
(* go through all cities *)
FOR i := Low(austria) TO High(austria) DO BEGIN
FOR k := Low(cities) TO High(cities) DO BEGIN
austria[i, k] := CIS_CERO;
END;
END;
END;
(*--------------------------------------------------------------------------*)
FUNCTION SplitCoordinate(coordinate: STRING; VAR row, column: MAP_INDEX): BOOLEAN;
VAR
code1, code2: INTEGER;
BEGIN
Val(coordinate[1], row, code1);
Val(coordinate[2], column, code2);
(* set if splitting worked *)
SplitCoordinate := (code1 + code2) = 0;
END;
(*--------------------------------------------------------------------------*)
FUNCTION GetCityInfectionState(row, column: MAP_INDEX): BYTE;
BEGIN
GetCityInfectionState := austria[row, column];
END;
(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates
raise the infection-index of the city equal to incoming coordinates by 1
=> do nothing if index is CIS_THREE already
----------------------------------------------------------------------------*)
PROCEDURE RaiseInfectionIndex(row, column: MAP_INDEX);
VAR
state: BYTE;
BEGIN
state := austria[row, column];
CASE state OF
CIS_CERO: state := CIS_ONE;
CIS_ONE:
state := CIS_TWO;
CIS_TWO:
state := CIS_THREE;
END;
austria[row, column] := state;
END;

(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates


lower the infection-index of the city equal to incoming coordinates by 1
=> do nothing if index is CIS_CERO already
----------------------------------------------------------------------------*)
PROCEDURE LowerInfectionIndex(row, column: MAP_INDEX);
VAR
state: BYTE;
BEGIN
state := austria[row, column];
CASE state OF
CIS_ONE:
state := CIS_CERO;
CIS_TWO:
state := CIS_ONE;
CIS_THREE: state := CIS_TWO;
END;
austria[row, column] := state;
END;
(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates
check if incoming coordinates are inside of array-bounds
----------------------------------------------------------------------------*)
FUNCTION InBounds(row, column: MAP_INDEX): BOOLEAN;
BEGIN
InBounds := (row >= 1) and (row <= 8) and (column >= 1) and (column <= 8);
END;
(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates
check if in bounds and if current coordinates are not locked
----------------------------------------------------------------------------*)
FUNCTION InBoundsAndNotLocked(row, column: MAP_INDEX): BOOLEAN;
BEGIN
InBoundsAndNotLocked := InBounds(row, column)
AND ((row <> senderRow) OR (column <> senderColumn));
END;
(*--------------------------------------------------------------------------*)
PROCEDURE InfectCity(row, column: MAP_INDEX);
VAR
state: BYTE;
BEGIN
state := GetCityInfectionState(row, column);
IF state < CIS_TWO THEN BEGIN
RaiseInfectionIndex(row, column);
END
ELSE IF state <> CIS_THREE THEN BEGIN
RaiseInfectionIndex(row, column);
IF InBounds(row - 1, column) THEN
InfectCity(row - 1, column);
END;
IF InBounds(row + 1, column) THEN
InfectCity(row + 1, column);
END;
IF InBounds(row, column - 1) THEN
InfectCity(row, column - 1);
END;
IF InBounds(row, column + 1) THEN
InfectCity(row, column + 1);
END;
END;
END;

BEGIN

BEGIN

BEGIN

BEGIN

(*---------------------------------------------------------------------------[IN]: row, column ....... city-coordinates


gives back the infection-sum of the neighbour cities of incoming row/column
----------------------------------------------------------------------------*)
FUNCTION GetInfectedCitiesAround(row, column: MAP_INDEX): INTEGER;
VAR
count: INTEGER;
BEGIN
(* check how much infections are around row/colunn *)
count := 0;
IF austria[row - 1, column] > CIS_CERO THEN Inc(count);
IF austria[row + 1, column] > CIS_CERO THEN Inc(count);
IF austria[row, column - 1] > CIS_CERO THEN Inc(count);
IF austria[row, column + 1] > CIS_CERO THEN Inc(count);
GetInfectedCitiesAround := count;
END;
(*---------------------------------------------------------------------------if the [IN/OUT] ampules-Rest is more then one, give back one, an decrease the
the rest.
----------------------------------------------------------------------------*)
FUNCTION GetOneOfTheRest(VAR ampulesRest: INTEGER): INTEGER;
BEGIN
GetOneOfTheRest := 0;
IF ampulesRest > 0 THEN BEGIN
Dec(ampulesRest);
GetOneOfTheRest := 1;
END;
END;
(*--------------------------------------------------------------------------*)
PROCEDURE SetSender(row, column: MAP_INDEX);
BEGIN
senderRow := row;
senderColumn := column;
END;
(*---------------------------------------------------------------------------[IN]: infectedCitiesAround ..... the cities which are infected around the actual
[IN]: ampulesTotal ............. the ampules available
[OUT]: ampulesPerCity .......... gives back how many ampules each city gets
[OUT]: ampulesRest ............. the rest which has to be forwarded
calculate the ampules for each city and the rest
----------------------------------------------------------------------------*)
PROCEDURE GetAmpules(infectedCitiesAround, ampulesTotal: INTEGER;
VAR ampulesPerCity, ampulesRest: INTEGER);
BEGIN
ampulesPerCity := ampulesTotal DIV infectedCitiesAround;
ampulesRest := 0;
IF (ampulesPerCity = 0) and (ampulesTotal < infectedCitiesAround) THEN BEGIN
ampulesPerCity := 1;
ampulesRest := infectedCitiesAround * -1;
END;
ampulesRest := ampulesRest + (ampulesTotal MOD infectedCitiesAround);
END;

(*--------------------------------------------------------------------------*)
PROCEDURE HealCity(row, column: MAP_INDEX; ampules: INTEGER);
(* check if the city is infected, and if the incoming coordinates are locked
or not and if there are enough ampules available *)
FUNCTION CheckOK(row, column: MAP_INDEX; amp: INTEGER): BOOLEAN;
BEGIN
CheckOK := (GetCityInfectionState(row, column) > CIS_CERO)
AND InBoundsAndNotLocked(row, column)
AND (amp > 0);
END;
VAR
infectedCitiesAround, ampulesPerCity, ampulesRest: INTEGER;
BEGIN
IF ampules > 0 THEN BEGIN
(* > if city is not infected, waste all ampules and do nothing
> if infected, heal until is healthy *)
IF GetCityInfectionState(row, column) > CIS_CERO THEN BEGIN
LowerInfectionIndex(row, column);
SetSender(row, column);
HealCity(row, column, ampules - 1);
END
ELSE BEGIN
(* returns the number of infected neighbours *)
infectedCitiesAround := GetInfectedCitiesAround(row, column);
(* if not more then one infected city - do nothing *)
IF infectedCitiesAround > 0 THEN BEGIN
(* get the number of ampules for each city around and the rest *)
GetAmpules(infectedCitiesAround, ampules, ampulesPerCity, ampulesRest);
(* start recursion
-> check before run if in bounds, locked, ... seh "CheckOK" *)
IF CheckOK(row - 1, column, ampules) THEN BEGIN
SetSender(row, column);
HealCity(row - 1, column, ampulesPerCity + GetOneOfTheRest(ampulesRest));
Dec(ampules);
END;
IF CheckOK(row + 1, column, ampules) THEN BEGIN
HealCity(row + 1, column, ampulesPerCity + GetOneOfTheRest(ampulesRest));
Dec(ampules);
END;
IF CheckOK(row, column - 1, ampules) THEN BEGIN
HealCity(row, column - 1, ampulesPerCity + GetOneOfTheRest(ampulesRest));
Dec(ampules);
END;
IF CheckOK(row, column + 1, ampules) THEN BEGIN
HealCity(row, column + 1, ampulesPerCity + GetOneOfTheRest(ampulesRest));
END;
END;
END;
END;
END;
BEGIN
END.

Potrebbero piacerti anche