program BlackBoxAtom; { Solution to the 1999 British Informatics Olympiad exam question 2: Black Box (Atom) Solution copyright (c) 1999 The British Informatics Olympiad (BIO). This program may be freely copied by persons or organisations involved in the British Informatics Olympiad or the International Olympiad in Informatics, on condition that no changes are made and this notice is not altered. Distribution for profit is forbidden unless permission is first obtained in writing from the BIO. This program is for educational purposes only and comes with no warranty, implied or otherwise, as to its fitness for any purpose. Author: Antony Rix Internet: http://www.christs.cam.ac.uk/bio/ E-mail: a.rix@lineone.net S-mail: The British Informatics Olympiad Christ's College Cambridge CB2 3BU United Kingdom } { Key constants. } const Blank = 0; const Atom = 1; const Ray = 2; const Hit = 3; var { Array holding board. } Board: array[0..11,0..11] of integer; { Set up a blank board } procedure init_board; var i, j: integer; begin for i := 0 to 11 do for j := 0 to 11 do Board[i][j] := Blank; end; { Clear the trace of a ray from the board } procedure reset_board; var x, y: integer; begin for x := 0 to 11 do for y := 0 to 11 do case Board[x][y] of Blank: Board[x][y] := Blank; Atom: Board[x][y] := Atom; Ray: Board[x][y] := Blank; Hit: Board[x][y] := Atom; end; end; { Display the current board. } procedure show_board; var x, y: integer; begin for y := 10 downto 1 do begin for x := 1 to 10 do case Board[x][y] of Blank: write( '.' ); Atom: write( 'A' ); Ray: write( '+' ); Hit: write( '*' ); end; writeln; end; end; { Follow the path of the ray. } procedure trace_ray( side: char; pos: integer ); var direct: integer; x, y, nx, ny: integer; begin { Starting position and direction } if side = 'B' then begin direct := 0; x := pos; y := 1; end else if side = 'L' then begin direct := 1; y := pos; x := 1; end else if side = 'T' then begin direct := 2; x := pos; y := 10; end else if side = 'R' then begin direct := 3; y := pos; x := 10; end else exit; { Follow ray until it runs out of the box } while (x > 0) and (x < 11) and (y > 0) and (y < 11) do begin Board[x][y] := Ray; { Find new position then apply the rules } nx := x; ny := y; case direct of 0: ny := y + 1; 1: nx := x + 1; 2: ny := y - 1; 3: nx := x - 1; end; { If absorbed, show the hit and return } if Board[nx][ny] = Atom then begin Board[nx][ny] := Hit; show_board; writeln( 'Absorbed' ); exit; end; { If reflected, simply return - the ray will retrace its path } if (direct = 0) or (direct = 2) then begin if (Board[nx-1][ny] = Atom) and (Board[nx+1][ny] = Atom) then begin show_board; writeln( 'Reflected' ); exit; end; end else begin if (Board[nx][ny-1] = Atom) and (Board[nx][ny+1] = Atom) then begin show_board; writeln( 'Reflected' ); exit; end; end; { Check for a deflection. If we deflect, move back to the last position and change direction. } if (direct = 0) or (direct = 2) then begin if Board[nx-1][ny] = Atom then begin direct := 1; ny := y; end; if Board[nx+1][ny] = Atom then begin direct := 3; ny := y; end; end else begin if Board[nx][ny-1] = Atom then begin direct := 0; nx := x; end; if Board[nx][ny+1] = Atom then begin direct := 2; nx := x; end; end; { Update position } x := nx; y := ny; end; show_board; { Find exit point } if x = 0 then writeln( 'Exits at L ', y ); if y = 0 then writeln( 'Exits at B ', x ); if x = 11 then writeln( 'Exits at R ', y ); if y = 11 then writeln( 'Exits at T ', x ); end; procedure part2a; var i, x, y: integer; side: char; begin init_board; writeln( 'Enter 5 co-ordinates in the form x y' ); for i := 1 to 5 do begin write( '>' ); readln( x, y ); Board[x][y] := Atom; end; show_board; writeln; { Main program loop: read in a character/number pair and then perform that action } repeat write( '>' ); readln( side, i ); side := upcase( side ); if ( (side = 'T') or (side = 'B') or (side = 'L') or (side = 'R') ) and (i > 0) and ( i < 11 ) then begin trace_ray( side, i ); reset_board; writeln; end else if side <> 'X' then writeln( 'Invalid input "', side, ' ', i, '"' ); until side = 'X'; writeln( 'Program finished.' ); end; begin part2a; end.