{
  CTU Open Contest 2002
  =====================
  Sample solution for the problem: maze

  Martin Kacer, Oct 2002
}

Program Labyrinth;

Const SIZE = 7;
	dUp = 1;
	dLeft = 2;
	dRight = 3;
	dDown = 4;
	dLast = 4;
	dR: Array[1..dLast] of Integer = (-1, 0, 0, 1);
	dC: Array[1..dLast] of Integer = (0, -1, 1, 0);
	dD: Array[1..dLast] of Integer = (dDown, dRight, dLeft, dUp);
	chVert: Char = '|';
	chHoriz: Char = '-';

Type
	TDir = Integer;
	TPiece = Array [1..dLast] of Boolean;
	TGame = Array[1..SIZE,1..SIZE] of TPiece;


{ determine whether it is possible to go from (R,C) to the given
direction. check also for the game margins }
Function CanGoThere (Var G: TGame; R,C: Integer; D: TDir) : Boolean;
Begin
	If (R + dR[D] < 1) or (R + dR[D] > SIZE)
		or (C + dC[D] < 1) or (C + dC[D] > 7) then CanGoThere := false
	else CanGoThere := G[R,C,D] and G[R+dr[D], C+dC[D], dD[D]];
End; { CanGoThere }


{ read the contents of the game field including the newline after
the last row }
Procedure ReadGame (Var G: TGame);
Var R, C: Integer;
	Ch: Char;
Begin
	For R:= 1 to SIZE do
	Begin
		For C:= 1 to SIZE do
		Begin
			Read (Ch);
			Read (Ch);
			G[R,C,dUp] := (Ch = chVert);
			Read (Ch);
			if ( C < SIZE ) then Read (Ch);
		End;
		ReadLn;
		For C:= 1 to SIZE do
		Begin
			Read (Ch);
			G[R,C,dLeft] := (Ch = chHoriz);
			Read (Ch);
			Read (Ch);
			G[R,C,dRight] := (Ch = chHoriz);
			if ( C < SIZE ) then Read (Ch);
		End;
		ReadLn;
		For C:= 1 to SIZE do
		Begin
			Read (Ch);
			Read (Ch);
			G[R,C,dDown] := (Ch = chVert);
			Read (Ch);
			if ( C < SIZE ) then Read (Ch);
		End;
		ReadLn;
		ReadLn;
	End;
End; { ReadGame }


{read the description of an extra piece including the trailing empty line}
Procedure ReadPiece (Var P: TPiece);
Var Ch: Char;
Begin
	Read (Ch); Read (Ch); P[dUp] := (Ch = chVert); Read (Ch); ReadLn;
	Read (Ch); P[dLeft] := (Ch = chHoriz); Read (Ch);
	Read (Ch); P[dRight] := (Ch = chHoriz); ReadLn;
	Read (Ch); Read (Ch); P[dDown] := (Ch = chVert); Read (Ch); ReadLn;
	ReadLn;
End;


{ find the path from (R1,C1) to (R2,C2) }
Function FindPath (Var G: TGame; R1, C1, R2, C2: Integer) : Boolean;
Var QR, QC: Array [1..SIZE*SIZE] of Integer;
	QB, QE: Integer;
	Vis: Array [1..SIZE, 1..SIZE] of Boolean;
	R, C: Integer;
	D: TDir;
Begin
	For R := 1 to SIZE do For C := 1 to SIZE do Vis[R,C] := false;
	QE := 2;  QB := 1;
	QR[1] := R1;  QC[1] := C1;
	Vis[R1,C1] := true;
	While (QB < QE) do
	Begin
		R := QR[QB];  C := QC[QB];
		Inc (QB);
		For D := 1 to dLast do
			If CanGoThere (G, R, C, D) then
			Begin
				If not Vis[R + dR[D], C + dC[D]] then
				Begin
					QR[QE] := R + dR[D];
					QC[QE] := C + dC[D];
					Vis[R + dR[D], C + dC[D]] := true;
					Inc (QE);
				End;
			End;
	End;
	FindPath := Vis[R2,C2];
	{DBG: WriteLn (Vis[R2,C2], ' <- ', R1, C1, ',', R2, C2);}
End; { FindPath }


{ rotate the piece }
Procedure PieceRotate (Var P: TPiece);
Var X: Boolean;
Begin
	X := P[dUp];
	P[dUp] := P[dRight];  P[dRight] := P[dDown];
	P[dDown] := P[dLeft];  P[dLeft] := X;
End;


{ make one move: shift the given row/column one position into the
given direction and insert the new piece into it;
return false, if the (R2,C2) is removed away from the desk;
set (R1,C1) to a new position if it has been moved
}
Function MoveUp (Var G: TGame; C: Integer; Var R1, C1: Integer;
		Var R2, C2: Integer; P: TPiece) : Boolean;
Var R: Integer;
Begin
	MoveUp := (R2 <> 1) or (C2 <> C);
	If (C1 = C) then
	Begin
		Dec (R1);
		If (R1 < 1) then R1 := SIZE;
	End;
	If (C2 = C) then Dec (R2);
	For R := 1 to SIZE-1 do G[R,C] := G[R+1,C];
	G[SIZE,C] := P;
	{DBG: WriteLn ('Up: ', C);}
End;

Function MoveDown (Var G: TGame; C: Integer; Var R1, C1: Integer;
		Var R2, C2: Integer; P: TPiece) : Boolean;
Var R: Integer;
Begin
	MoveDown := (R2 <> SIZE) or (C2 <> C);
	If (C1 = C) then
	Begin
		Inc (R1);
		If (R1 > SIZE) then R1 := 1;
	End;
	If (C2 = C) then Inc (R2);
	For R := SIZE downto 2 do G[R,C] := G[R-1,C];
	G[1,C] := P;
	{DBG: WriteLn ('Down: ', C);}
End;

Function MoveLeft (Var G: TGame; R: Integer; Var R1, C1: Integer;
		Var R2, C2: Integer; P: TPiece) : Boolean;
Var C: Integer;
Begin
	MoveLeft := (C2 <> 1) or (R2 <> R);
	If (R1 = R) then
	Begin
		Dec (C1);
		If (C1 < 1) then C1 := SIZE;
	End;
	If (R2 = R) then Dec (C2);
	For C := 1 to SIZE-1 do G[R,C] := G[R,C+1];
	G[R,SIZE] := P;
	{DBG: WriteLn ('Left: ', R);}
End;

Function MoveRight (Var G: TGame; R: Integer; Var R1, C1: Integer;
		Var R2, C2: Integer; P: TPiece) : Boolean;
Var C: Integer;
Begin
	MoveRight := (C2 <> SIZE) or (R2 <> R);
	If (R1 = R) then
	Begin
		Inc (C1);
		If (C1 > SIZE) then C1 := 1;
	End;
	If (R2 = R) then Inc (C2);
	For C := SIZE downto 2 do G[R,C] := G[R,C-1];
	G[R,1] := P;
	{DBG: WriteLn ('Right: ', R);}
End;


{ read and completely solve one game }
Function OneGame (R1X, C1X, R2X, C2X: Integer) : Boolean;
Var R1, C1, R2, C2: Integer;
	G, GX: TGame;
	P: TPiece;
	Rotate, Num: Integer;
Begin
	OneGame := false;
	ReadLn;
	ReadGame (GX);
	ReadPiece (P);
	For Rotate := 1 to 4 do
	Begin
		For Num := 1 to (SIZE div 2) do
		Begin
			G:=GX; C1:=C1X; R1:=R1X; C2:=C2X; R2:=R2X;
			If MoveUp (G, Num*2, R1, C1, R2, C2, P) then
				If FindPath (G, R1, C1, R2, C2) then OneGame := true;
			G:=GX; C1:=C1X; R1:=R1X; C2:=C2X; R2:=R2X;
			If MoveDown (G, Num*2, R1, C1, R2, C2, P) then
				If FindPath (G, R1, C1, R2, C2) then OneGame := true;
			G:=GX; C1:=C1X; R1:=R1X; C2:=C2X; R2:=R2X;
			If MoveLeft (G, Num*2, R1, C1, R2, C2, P) then
				If FindPath (G, R1, C1, R2, C2) then OneGame := true;
			G:=GX; C1:=C1X; R1:=R1X; C2:=C2X; R2:=R2X;
			If MoveRight (G, Num*2, R1, C1, R2, C2, P) then
				If FindPath (G, R1, C1, R2, C2) then OneGame := true;
		End;
		PieceRotate (P);
	End;
End; { OneGame }


Var R1, C1, R2, C2 : Integer;

Begin
	Repeat
		ReadLn (R1, C1, R2, C2);
		If ( R1 > 0 ) then
		Begin
			If OneGame (R1, C1, R2, C2) then
				WriteLn ('You can win in one move.')
			else
				WriteLn ('Bad luck!');
		End;
	Until (R1 = 0);
End.
