{****************************************************************************** MINE Mine is the classic game where a field of hidden mines is presented, and the user tries to find the mines based on mine counts in adjacent squares. ******************************************************************************} program mine(input, output); const maxxs = 8; { size of grid } maxys = 8; maxmine = 10; { number of mines to place } type square = record { individual square } mine: boolean; { mine exists at square } vis: boolean { square is uncovered } end; point = record x, y: integer end; fixed offset: array [1..8] of point = array record 0, -1 end, { up } record +1, -1 end, { upper right } record +1, 0 end, { right } record +1, +1 end, { lower right } record 0, +1 end, { down } record -1, +1 end, { lower left } record -1, 0 end, { left } record -1, -1 end { upper left } end; var { playing board } board: array [1..maxxs, 1..maxys] of square; rndseq: integer; { randomizer } x, y: integer; { user move coordinates } done: boolean; { game over } c: char; { user response } viscnt: integer; { visible squares count } {****************************************************************************** Find random number Finds a random number between the given top and 1. ******************************************************************************} function rand(top: integer): integer; const a = 16807; m = 2147483647; var gamma: integer; begin gamma := a*(rndseq mod (m div a))-(m mod a)*(rndseq div (m div a)); if gamma > 0 then rndseq := gamma else rndseq := gamma+m; rand := rndseq div (m div top)+1 end; {****************************************************************************** Find adjacent mines Finds the number of mines adjacent to a given square. ******************************************************************************} function adjacent(x, y: integer): integer; var mines: 0..8; { number of mines } xn, yn: integer; { neighbor coordinates } i: 1..8; { index for move array } begin mines := 0; { clear mine count } for i := 1 to 8 do begin { process points of the compass } xn := x+offset[i].x; { find neighbor locations } yn := y+offset[i].y; if (xn >= 1) and (xn <= maxxs) and (yn >= 1) and (yn <= maxys) then { valid location } if board[xn, yn].mine then mines := mines+1 { count mines } end; adjacent := mines { return the number of mines } end; {****************************************************************************** Set adjacent squares visable Sets all of the valid adjacent squares visable. If any of those squares are not adjacent to a mine, then the neighbors of that square are set visable, etc. (recursively). This is done to "rip" grids of obviously empty neighbors off the board. ******************************************************************************} procedure visadj(x, y: integer); var xn, yn: integer; { neighbor coordinates } i: 1..8; { index for move array } begin for i := 1 to 8 do begin { process points of the compass } xn := x+offset[i].x; { find neighbor locations } yn := y+offset[i].y; if (xn >= 1) and (xn <= maxxs) and (yn >= 1) and (yn <= maxys) then if not board[xn, yn].vis then begin { not already visable } { valid location } board[xn, yn].vis := true; { set visable } if adjacent(xn, yn) = 0 then visadj(xn, yn) { perform recursively } end end end; {****************************************************************************** Display board Displays the playing board. ******************************************************************************} procedure display; var x: integer; y: integer; cnt: 0..8; { count of adjacent mines } begin writeln; { scan screen } writeln(' 12345678'); for y := 1 to maxys do begin write(y:1, ': '); for x := 1 to maxxs do with board[x, y] do if vis then begin if mine then write('*') else begin cnt := adjacent(x, y); { find adjacent mine count } if cnt = 0 then write('.') { no adjacent } else write(chr(cnt+ord('0'))) { place the number } end end else write('='); writeln { next line } end; writeln end; {****************************************************************************** Initalize board Initalizes the board to "none", then places the required fish and sharks at random. The ages are set at random with the breeding time for the object as the top. ******************************************************************************} procedure clear; var x: integer; y: integer; n: integer; begin for x := 1 to maxxs do { clear minefield } for y := 1 to maxys do with board[x, y] do begin mine := false; { set no mine } vis := false { set not visable } end; for n := 1 to maxmine do begin { place mines } repeat x := rand(maxxs); y := rand(maxys) until not board[x, y].mine; { no mine exists at square } board[x, y].mine := true { place mine } end end; {****************************************************************************** Main process ******************************************************************************} begin writeln('******* Mine game 1.0 ********'); rndseq := 1; clear; { set up board } display; { display board } done := false; { set game in progress } repeat { enter user moves } write('Move y: '); readln(y); write('Move x: '); readln(x); if (x < 1) or (x > maxxs) or (y < 1) or (y > maxys) then writeln('*** User move invalid ***') else begin { user move valid } board[x, y].vis := true; { set that location visable } if board[x, y].mine then begin { mine found } { make all mines visable } for y := 1 to maxys do for x := 1 to maxxs do if board[x, y].mine then board[x, y].vis := true; writeln; writeln('*** YOU HIT A MINE ! ***'); display; { display that } repeat { get answer } write('Play again (y/n): '); readln(c) until c in ['Y', 'y', 'N', 'n']; if c in ['N', 'n'] then done := true { set game over } else clear { start new game } end else begin { valid hit } if adjacent(x, y) = 0 then { no adjacent mines } visadj(x, y); { clean up adjacent spaces } { now, the player may have won. we find this out by counting all of the visable squares, and seeing if the number of squares left is equal to the number of mines } viscnt := 0; for y := 1 to maxys do for x := 1 to maxxs do if board[x, y].vis then viscnt := viscnt+1; { count visible } if maxxs*maxys-viscnt = maxmine then begin { player wins } writeln; writeln(' *** YOU WIN ! ***'); writeln; repeat { get answer } write('Play again (y/n): '); readln(c) until c in ['Y', 'y', 'N', 'n']; if c in ['N', 'n'] then done := true { set game over } else clear { start new game } end end; if not done then display { redisplay board } end until done { game complete } end.