Program labyrinttiuus;
uses winmouse,graph, wincrt,math,sysutils,DateUtils;
CONST xkoko = 100;
	  ykoko = 80;
	  maxstep	=	999999;
	  morkoja	=	80;
TYPE
		XTYPE 	=	1..xkoko;
		YTYPE	=	1..ykoko;
		koords	=	RECORD {MÖRKÖJEN KOORDINAATAT!!}
						x: 1..xkoko;
						y: 1..ykoko;		
					END;
VAR	  	labyrintti	: ARRAY[1..xkoko,1..ykoko] OF smallInt;
		MOROT	:	ARRAY[1..morkoja] OF koords;
		step	:	longInt;
		yritauudestaan	: 	BOOLEAN;
		px, py	:	shortInt;
		key		:	char;
		lopussa	:	BOOLEAN;
		gd,gm: integer;
	    dx, dy	:	shortInt;
	    lev,kork	:	shortInt;
	    error	:	SmallInt;
	    ok, lopeta	:	BOOLEAN;
	    TheLine	:	String;
	    aikalaskuri	:	LongInt;
	    xkoord, ykoord, vanhax, vanhay	:	ShortInt;
	    a,b		: integer;
	    r	:	SmallInt; 
	    now1, now2  :  TDateTime;
	    aika	:	SmallInt;
	    

PROCEDURE arvolabyrintti;
VAR i	:	XTYPE;
	j	:	YTYPE;
	ruutu: shortint;
	eikelpaa	: BOOLEAN;
BEGIN
	FOR i:=1 TO xkoko DO
		FOR j:=1 TO ykoko DO
			BEGIN
				IF Random(3)+1=2 THEN ruutu:=1
				ELSE
					ruutu:= Random(2)+1;
					labyrintti[i,j]:= ruutu;
			END;
	{Arvotaan myös MORKÖJEN alkukoordinaatat}
	FOR i:=1 TO morkoja DO 
	BEGIN
		eikelpaa:=FALSE;
		REPEAT
			xkoord:=Random(xkoko)+1;
			ykoord:=Random(ykoko)+1;
			IF (xkoord<(px+15)) AND (xkoord>(px-15)) THEN eikelpaa:=TRUE;
		UNTIL (labyrintti[xkoord,ykoord]=1) AND eikelpaa=FALSE;
		MOROT[i].x:=xkoord;
		MOROT[i].y:=ykoord;
		labyrintti[xkoord,ykoord]:=4;
	END;
END;
PROCEDURE paastaanulos; {Tarkistetaan satunnaiskävelyllä päästäänkö 
edes ulos labyrintista ainakin jotain reittiä. Tämä ei tietenkään ole paras 
mahdollinen ja tehokkain tapa, mutta riittävän nopea nykytietokoneille ja 
helpoin ohjelmoida.}
VAR x	:	XTYPE;
	y	:	YTYPE;
	askelx, askely: shortint;
BEGIN
	yritauudestaan:= FALSE;
	{jos arvotussa labyrintissa arvottiin pelaajan kohdalle tiili eli luku 2, niin turha edes yrittää}
	if (labyrintti[px,py] = 2) THEN yritauudestaan:= TRUE;
	x:= px;
	y:= py;
	step:=0;
	REPEAT 
		BEGIN
			REPEAT
				askelx:= -2 + (random(3) + 1); {Jomman kumman askeleen täytyy olla nolla.}
				askely:= -2 + (random(3) + 1); {Siis vain askeleet pääilmansuuntiin ovat sallittuja.}
				step:= step + 1;
			UNTIL (((askelx = 0) OR (askely = 0)) AND (labyrintti[x+askelx, y+askely] <> 2) OR (step>maxstep));  
			if (step > maxstep) THEN yritauudestaan:= true;
			x:= x + askelx;
			y:= y + askely;
		END;
	UNTIL ((x<2) or (x>xkoko) or (y<2) or (y>ykoko)) or (yritauudestaan = true); 
	{ollaan päästy reunaan eli ulos tai luovutaan koko yrityksestä}
END;
PROCEDURE tulostalahialue;
	VAR i,j	:	shortInt;
	x1,x2,y1,y2 : shortInt;
BEGIN
	x1:= 0;
	x2:= xkoko+1;
	y1:= 0;
	y2:= ykoko+1;
	FOR j:=(y1+1) TO y2 DO
		BEGIN
			FOR i:=(x1+1) TO x2 DO
				BEGIN
					case (labyrintti[i, j]) of
						1 : SetFillStyle(SolidFill,white); 
						2 : SetFillStyle(SolidFill,blue); 
						3 : SetFillStyle(SolidFill,red);
						4 : SetFillStyle(SolidFill,yellow);
					end;
					a:=(i-x1+1)*lev;
					b:=(j-y1+1)*kork;
					if ((i<2) or (i>xkoko) or (j<2) or (j>ykoko)) THEN SetFillStyle(SolidFill,green);
					bar(a-lev,b-kork,a,b);
				END;	
		END;
END;
PROCEDURE piirraruutu(x1,y1,x2,y2,vari:ShortInt); {piirtää joko mörön tai pelaajan kohtaan
x1,y1 ja valkoistaa edellisen ruudun x2,y2}
BEGIN
	case (vari) of
		3 : SetFillStyle(SolidFill,red);
		4 : SetFillStyle(SolidFill,yellow);
	end;
	a:=x1*lev;
	b:=y1*kork;
	bar(a,b,a+lev,b+kork);
	SetFillStyle(SolidFill,white);
	a:=x2*lev;
	b:=y2*kork;
	bar(a,b,a+lev,b+kork);
END;
PROCEDURE alusta;
BEGIN
	Randomize;
	dx:=trunc(xkoko/2); 
	dy:=trunc(ykoko/2); 

	 initmouse;
  gd := detect;
  initgraph(gd,gm,'');
    error := graphResult;
  if (error <> grOk) Then
    begin
    writeln('grapich state is not supported!');
    halt(1);
    end;
    
	lev:=trunc(GetMaxX / (2 * dx + 1));
	kork:=trunc(GetMaxY / (2 * dy + 1));    
    
	px:= trunc(xkoko/2); 
	py:= trunc(ykoko/2); 

	yritauudestaan:=true;
	repeat
		write('Odota, arvon labyrinttia.');
		arvolabyrintti;
		paastaanulos;
	until yritauudestaan = false;
	labyrintti[px,py]:=3;
	tulostalahialue;
	 setTextStyle(defaultFont,horizDir,2);
END;
PROCEDURE tv;
BEGIN
if ((px<2) or (px>xkoko) or (py<2) or (py>ykoko)) THEN
	lopussa:=TRUE;
END;
PROCEDURE huomauta;
BEGIN
	Writeln('Ei kannata hakata kupolia muuriin!!');
END;
PROCEDURE RAJAHDYS;
VAR pxword,pyword	: 	word;
BEGIN
	Writeln('RAJAHDYS!!!!!!!!!!!!!!!!!!!!!');
	pxword:=trunc((px/xkoko)*GetMAxX);
	pyword:=trunc((py/ykoko)*GetMaxY);
	FOR r:=1 TO trunc(GetMaxY/10) DO
	BEGIN
		SetFillStyle(SolidFill,Random(GetMAxColor));
		FillEllipse(pxword,pyword,30*r,30*r);
	END;
	halt(2);
END;
PROCEDURE tarkistasuunta(dx,dy:ShortInt); {dx on joko -1 tai 1 samoin kuin dy}
BEGIN
	IF labyrintti[px+dx,py+dy]=4 THEN RAJAHDYS;
	if labyrintti[px+dx,py+dy]=2 THEN huomauta
	ELSE
		BEGIN
		vanhax:=px; vanhay:=py;
		labyrintti[px,py]:=1;
		px:=px+dx; py:=py+dy; 
		ok:=true;
		tv;
		labyrintti[px,py]:=3;
		piirraruutu(px,py,vanhax,vanhay,3);
		IF labyrintti[px,py]=4 THEN RAJAHDYS;
	END;
	
END;

PROCEDURE siirramorkoja;
VAR i, vanhax, vanhay, askelx, askely, yrityksia	:	ShortInt;
BEGIN
	FOR i:=1 TO morkoja DO
	BEGIN
		vanhax:=MOROT[i].x;
		vanhay:=MOROT[i].y;
		yrityksia:=0;
		REPEAT
			REPEAT
				yrityksia:=yrityksia+1;
				askelx:=-2+(random(3)+1);
				askely:=-2+(random(3)+1);
			UNTIL ((askelx=0) XOR (askely=0));  
		UNTIL (labyrintti[vanhax+askelx,vanhay+askely]=1) OR (yrityksia>20) OR (labyrintti[vanhax+askelx,vanhay+askely]=3);
		IF labyrintti[vanhax+askelx,vanhay+askely]=3 THEN RAJAHDYS;
		IF (yrityksia<20) AND (labyrintti[vanhax+askelx,vanhay+askely]=1) THEN
		BEGIN
			MOROT[i].x:=vanhax+askelx; MOROT[i].y:=vanhay+askely;
			piirraruutu(vanhax+askelx,vanhay+askely,vanhax,vanhay,4);
			IF labyrintti[MOROT[i].x,MOROT[i].y]=3 THEN RAJAHDYS;
		END;
		IF labyrintti[MOROT[i].x,MOROT[i].y]=3 THEN RAJAHDYS;
	END;
END;

begin
	alusta;
	ok:=false;
	lopeta:=false;
	lopussa:=false;
	now1:=Now;
	repeat 
			REPEAT
				aikalaskuri:=0;
				siirramorkoja;
				
				REPEAT
					aikalaskuri:=aikalaskuri+1;
					 {Tehotonta! Senkun lasketaan kymmeneen miljoonaan ja kasvatetaan aikalaskuria, 
					mutta mihinkäs tässä kiire näppäinpainallusta odotellessa}
				UNTIL (aikalaskuri=20000000) OR KeyPressed;
				now2:=Now;
				aika:=(trunc(((100000*(now2-now1)))));
				Writeln('Aikaa jaljella vain',60-aika,' sekuntia!!');
				IF aika>60 THEN RAJAHDYS;
				aikalaskuri:=0;
				siirramorkoja;
			    IF KeyPressed THEN
			    BEGIN
				    key:=readkey;
					case key of
				  	#72 : tarkistasuunta(0,-1);
				  	#80 : tarkistasuunta(0,1);
				  	#75 : tarkistasuunta(-1,0); 
				  	#77	: tarkistasuunta(1,0);
				  	'a' : lopeta:=true; 
			  		end;
		  		END; 
		  	UNTIL ok or lopeta or lopussa;
			ok:=false; {asetetaan taas falseksi seuraavaa näppäimen painallusta varten}

	UNTIL lopeta or lopussa;
	IF lopussa THEN WRITELN('LOISTAVAA!! PAASIT LABYRINTISTA ULOS');
	
end.