//author chromos
//chromos@chromos.cz
//released 2015-2017
//version 0.18
SUBRMAIN();
SUBRPREAMBLE();
SUBRINPUTCOORDS();
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
SUBRFROMTO();
FUNCDMTODEG();
SUBRVALIDCOORDS();
SysAngle:=HAngle; //remember Home setting
SysFormat:=HFormat;
NewCache; //flag for skipping inputing data
GK; //for GETKEY
Counter; //for inputing coords
FC; //Are entered all coord digits?
Loop; //for FOR-DO (vars A..Z)
Loop1;
Loop2;
Loop3;
Loop4;
Loop5;
Loop6;
Loop7;
Loop8;
Loop9;
Loop10;
Loop11;
Loop12;
Loop13;
Loop14;
Loop15;
Loop16;
Loop17;
Loop18;
Loop19;
Loop20;
Loop21;
Loop22;
Loop23;
Loop24;
Loop25;
Loop26;
Temp; //Temp
Temp1;
Temp2;
TempList; //for looped variable numbers
TempFor; //for making nested loop via EXPR
TempEnd; //for making nested loop via EXPR
TempBody; //for making nested loop via EXPR
DigitSum; //digit sum for coordinates
SubDigitSum; //digit sum for KNOWN part of coords
VarDigitSum; //digit sum for variables only
PublLat; //Published coords in DD.DDDD (cache isn't there)
PublLon; //Published coords in DD.DDDD (cache isn't there)
Publinput; //flag for different input forms for unsolved and published coords
Dist; //Distance from published to solved coords
DMToDeg; //for FUNC DD°MM.MMM > DD.DDDDDD
EXPORT Current_Cache()
BEGIN
NewCache:=1;
IF (SIZE(L1)<>15 OR SIZE(L7)<>15) THEN
NewCache:=2;
PRINT();
PRINT("Sorry, it seems your data got corrupted. You must enter them again.
(Press any key to continue...)");
WAIT;
END;
SUBRMAIN();
END;
EXPORT New_Cache()
BEGIN
NewCache:=2;
SUBRMAIN();
END;
SUBRMAIN()
BEGIN
HAngle:=1;
HFormat:=0;
TempList:=MAKELIST("",X,1,1);
TempList:={};
IFTE(NewCache=2,L1:={},""); //Coords in L1
L2:={}; //List of variables
IFTE(NewCache=2,L3:={},""); //Values 'from' of variables in L2
IFTE(NewCache=2,L4:={},""); //Values 'to' of variables in L2
L5:={}; //List of expressions
L6:={}; //Lists of valid variable values
IFTE(NewCache=2,L7:={},""); //Starting coords
L8:={}; //Solved coords Lat
L9:={}; //Solved coords Lon
L0:={}; //Distance and bearing from starting published coords
// Preamble
//IFTE(NewCache==2,SUBRPREAMBLE(),"");
// Enter initial coords
IF NewCache==2 THEN
Publinput:="1";
SUBRINPUTCOORDS();
L7:=L1;
END;
PublLat:=EXPR(L7(1)+L7(2))+EXPR(L7(3)+L7(4)+"."+L7(5)+L7(6)+L7(7))/60;
PublLon:=EXPR(L7(8)+L7(9)+L7(10))+EXPR(L7(11)+L7(12)+"."+L7(13)+L7(14)+L7(15))/60;
// Enter unsolved coords
IF NewCache==2 THEN
Publinput:="";
SUBRINPUTCOORDS();
END;
// Enter digit sum if known
Temp:=0;
DigitSum:=0;
VarDigitSum:=0;
CHOOSE(Temp,"Enter digit sum for:","Whole coords","Variables only","Skip");
IF Temp==1 THEN
INPUT({{DigitSum,[0],{50,10,3}}},"Whole coords digit sum");
END;
IF Temp==2 THEN
INPUT({{VarDigitSum,[0],{50,10,3}}},"Vars only digit sum");
END;
// Extracting expressions (into L5) and variables (into L2) from L1
SubDigitSum:=0;
FOR Loop FROM 1 TO 15 DO
IF SIZE(LNAME(EXPR("'"+L1(Loop)+"'")))>0 THEN
L5(0):=L1(Loop);
L2:=UNION(L2,LNAME(EXPR("'"+L1(Loop)+"'")));
ELSE
SubDigitSum:=SubDigitSum+EXPR(L1(Loop));
END;
END;
L2:=EXECON("STRING(QUOTE&1)",L2);
L2:=SORT(L2);
// Initializing ranges of variables
IFTE(NewCache=2,L3:=MAKELIST(1,X,1,SIZE(L2)),"");
IFTE(NewCache=2,L4:=MAKELIST(20,X,1,SIZE(L2)),"");
// Recapitulation
PRINT();
PRINT(" RECAPITULATION");
TempList:=L1;
L1:=L7;
PRINT("Initial coords:");
SUBRPRINTINPUTCOORDS();
L1:=TempList;
PRINT("Unsolved coords:");
SUBRPRINTINPUTCOORDS();
PRINT("Variables: "+SIZE(L2));
PRINT("Expressions: "+SIZE(L5));
IF (SIZE(L2)<1 OR SIZE(L5)<2) THEN
PRINT("
GIVE ME AT LEAST ONE VARIABLE AND TWO EXPRESSIONS. BYE!");
KILL;
END;
IF DigitSum>0 THEN
PRINT("Digit sum is "+DigitSum+" for whole coords and "+(DigitSum-SubDigitSum)+" for unknown part.");
END;
IF VarDigitSum>0 THEN
PRINT("Digit sum for variables is "+VarDigitSum+".");
END;
PRINT("
(Press any key to continue...)");
WAIT;
// Edit ranges of variables
Temp=1;
CHOOSE(Temp,"Ranges of variables","Edit","Skip");
IF Temp==1 THEN
Temp:="";
Temp1:="";
Temp2:="";
FOR Loop FROM 1 TO SIZE(L2) DO
Temp:=Temp+"{L3("+Loop+"),[0],{40,10,"+Loop+"}},{L4("+Loop+"),[0],{60,10,"+Loop+"}}";
IFTE(Loop<SIZE(L2),Temp:=Temp+",","");
Temp1:=Temp1+STRING("'"+L2(Loop)+"' is FROM ")+","+STRING("TO ");
IFTE(Loop<SIZE(L2),Temp1:=Temp1+",","");
Temp2:=Temp2+STRING("Lower limit for '"+L2(Loop)+"'")+","+STRING("Upper limit for '"+L2(Loop)+"'");
IFTE(Loop<SIZE(L2),Temp2:=Temp2+",","");
END;
Temp:="INPUT({"+Temp+"},"+STRING("Ranges of variables")+",{"+Temp1+"},{"+Temp2+"})";
EXPR(Temp);
END;
// Computing valid coords
SUBRFROMTO();
// RESULTS
PRINT();
IF SIZE(L8)==0 THEN //Zero coords
PRINT("Ooops! 0 coords found!
Your input criteria are wrong!");
ELSE
FOR Loop1 FROM 1 TO SIZE(L2) DO //print ranges of variables
TempList:={};
FOR Loop2 FROM 1 TO SIZE(L6) DO
TempList(0):=L6(Loop2,Loop1);
END;
TempList:=SORT(TempList);
L3(Loop1):=TempList(1);
L4(Loop1):=TempList(0);
END;
FOR Loop FROM 1 TO SIZE(L3) DO
PRINT(L2(Loop)+" ∈ 〈"+L3(Loop)+";"+L4(Loop)+"〉");
END;
PRINT("");
IF SIZE(L8)==1 THEN //for 1 coord
PRINT("Congrats! You solved it!
Cache is here:");
PRINT(L8(1)+" "+L9(1)+" "+L0(1));
PRINT("
You can see this result in LIST Editor too:");
END;
IF SIZE(L8)>=2 AND SIZE(L8)<=10 THEN //for 2 to 10 coords
PRINT(SIZE(L8)+" coords found!");
FOR Loop FROM 1 TO SIZE(L8) DO
PRINT(L8(Loop)+" "+L9(Loop)+" "+L0(Loop));
END;
PRINT("
You can see these results in LIST Editor too:");
END;
IF SIZE(L8)>10 THEN //for more than 10 coords
PRINT(SIZE(L8)+" coords found!");
FOR Loop FROM 1 TO 10 DO
PRINT(L8(Loop)+" "+L9(Loop)+" "+L0(Loop));
END;
PRINT("
Only ten coords are listed here. For complete results look into LIST Editor:");
END;
PRINT("L8 and L9 contain found coords with values of alphabetically sorted variables in L6.
L0 contains distance and bearing from starting coords.
L3 and L4 contain boundaries for variables in L2.");
END;
PRINT("
(Press any key to exit Terminal...)");
// END of program
HAngle:=SysAngle; //Restore Home settings
HFormat:=SysFormat;
END;
// --- SUBROUTINES ---
SUBRPREAMBLE()
BEGIN
PRINT();
PRINT("This program helps geocachers to solve incomplete coordinates as seen in mystery or multi caches listings.
If you've ever seen something like this:
N50° 2(A-C).(B)(A+D)(E-F)
E013° 50.(F)(C-A)(D)
then this program is for you!
(Press any key to continue...)");
WAIT;
END;
SUBRINPUTCOORDS()
BEGIN
Counter:=0;
L1:=MAKELIST("#",X,1,15);
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
REPEAT
FC:=0;
REPEAT
GK:=GETKEY;
IF GK==49 AND Publinput=="" THEN
IF Counter<15 THEN
Counter:=Counter+1;
L1(Counter):="#";
Temp:="";
IF INPUT({{Temp,[2],{20,70,3}}},"Expression","Expr.","Variables must be in UPPERCASE! (e.g. A+B-4)","","")==0 THEN Counter:=Counter-1; END;
IF Temp<>"" THEN
IFERR(EXPR(Temp)) THEN
Counter:=Counter-1; MSGBOX("'"+Temp+"' isn't valid expression! Press OK to continue.");
ELSE
L1(Counter):="("+Temp+")";
END;
END;
END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF GK==47 THEN
IF Counter<15 THEN
Counter:=Counter+1;
L1(Counter) := "0";
END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF (GK>=42 AND GK<=44) THEN //digits 1-3
IF Counter<15 THEN
Counter:=Counter+1;
L1(Counter):=STRING(GK-41);
END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF (GK>=37 AND GK<=39) THEN //digits 4-6
IF Counter<15 THEN
Counter:=Counter+1;
L1(Counter):=STRING(GK-33);
END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF (GK>=32 AND GK<=34) THEN //digits 7-9
IF Counter<15 THEN
Counter:=Counter+1;
L1(Counter):=STRING(GK-25);
END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF GK==19 THEN
IF Counter>0 THEN L1(Counter):="#"; Counter:=Counter-1; END;
PRINT();
IFTE(Publinput=="1",PRINT("Enter INITIAL coords:"),PRINT("Enter UNSOLVED coords:"));
SUBRPRINTINPUTCOORDS();
SUBRPRINTINPUTCOORDSHELP();
END;
IF GK==4 THEN KILL; END;
UNTIL GK==30
END;
IF POS(L1,"#")<>0 THEN FC:=1; PRINT("You must fill in coords before you can continue!"); END;
UNTIL FC==0
END;
END;
SUBRPRINTINPUTCOORDS()
BEGIN
PRINT(" "+L1(1)+L1(2)+"° "+L1(3)+L1(4)+"."+L1(5)+L1(6)+L1(7)+"
"+L1(8)+L1(9)+L1(10)+"° "+L1(11)+L1(12)+"."+L1(13)+L1(14)+L1(15));
END;
SUBRPRINTINPUTCOORDSHELP()
BEGIN
PRINT("
Press '1'-'9' for entering coordinates,");
IF Publinput=="" THEN PRINT("'Space' for unknown digit expression,"); END;
PRINT("'Backspace' for backspace,
'Enter' for next step,
'Esc' for abort.
");
END;
SUBRFROMTO()
BEGIN
//number of possibilities
PRINT();
PRINT("No. of possibilities: "+IFTE(SIZE(L3)>=2,ΠLIST(L4-L3+1),L4(1)-L3(1)+1));
PRINT("
(Press any key to continue...)");
WAIT;
IF SIZE(L2)>=2 THEN //nested loops construction
TempFor:="";
TempEnd:="";
TempBody:="";
FOR Loop FROM 2 TO SIZE(L2) DO
TempFor:=TempFor+"FOR Loop"+STRING(Loop)+" FROM L3("+STRING(Loop)+") TO L4("+STRING(Loop)+") DO
";
TempEnd:=TempEnd+"END;
";
END;
TempBody:="SUBRVALIDCOORDS();
";
END;
PRINT();
PRINT("
Completed: 0 %");
FOR Loop1 FROM L3(1) TO L4(1) DO //main brute force cycle
IFTE(SIZE(L2)>=2,EXPR(TempFor+TempBody+TempEnd),SUBRVALIDCOORDS());
PRINT();
PRINT("
Completed: "+ROUND(100*(1+Loop1-L3(1))/(1+L4(1)-L3(1)),0)+" %");
END;
END;
FUNCDMTODEG(DMToDeg)
BEGIN
LOCAL FuncTemp1:="", FuncTemp2:="", FuncLoop;
FOR FuncLoop FROM 1 TO 3 DO
IF (MID(DMToDeg,FuncLoop,1)<>"°" AND MID(DMToDeg,FuncLoop,1)<>" ") THEN
FuncTemp1:=""+FuncTemp1+MID(DMToDeg,FuncLoop,1);
END;
END;
FOR FuncLoop FROM 4 TO DIM(DMToDeg) DO
IF (MID(DMToDeg,FuncLoop,1)<>"°" AND MID(DMToDeg,FuncLoop,1)<>" ") THEN
FuncTemp2:=""+FuncTemp2+MID(DMToDeg,FuncLoop,1);
END;
END;
DMToDeg:=EXPR(FuncTemp1)+EXPR(FuncTemp2)/60;
RETURN(DMToDeg);
END;
SUBRVALIDCOORDS()
BEGIN
FOR Loop FROM 1 TO SIZE(L2) DO
EXPR(L2(Loop)+":=Loop"+STRING(Loop));
END;
IFERR (EXPR(L5)) THEN
ELSE
Temp:=0;
Temp1:=-1;
CASE
IF DigitSum>0 THEN
Temp:=ΣLIST(EXPR(L5));
Temp1:=DigitSum-SubDigitSum;
END;
IF VarDigitSum>0 THEN
Temp:=ΣLIST(EXPR(L2));
Temp1:=VarDigitSum;
END;
END;
IF (Temp1==-1 OR Temp==Temp1) THEN
// IF ΠLIST(EXPR(L5+">=0") AND EXPR(L5+"<=9") AND EXPR("FP("+L5+")==0")) THEN
IF ΠLIST(EXECON("EXPR(&1)>=0 AND EXPR(&1)<=9 AND FP(EXPR(&1))==0",L5)) THEN
L8(0):=""+EXPR(L1(1))+EXPR(L1(2))+"° "+EXPR(L1(3))+EXPR(L1(4))+"."+EXPR(L1(5))+EXPR(L1(6))+EXPR(L1(7)); //Lat
L9(0):=""+EXPR(L1(8))+EXPR(L1(9))+EXPR(L1(10))+"° "+EXPR(L1(11))+EXPR(L1(12))+"."+EXPR(L1(13))+EXPR(L1(14))+EXPR(L1(15)); //Long
L6(0):=EXPR(L2);
Dist:=acos(sin(PublLat)*sin(FUNCDMTODEG(L8(0)))+cos(PublLat)*cos(FUNCDMTODEG(L8(0)))*cos(FUNCDMTODEG(L9(0))-PublLon));
IFERR(θ:=acos((sin(FUNCDMTODEG(L8(0)))-sin(PublLat)*cos(Dist))/(sin(Dist)*cos(PublLat)))) THEN
L0(0):=ROUND(6371*π/180*Dist,-3)+" km error°";
ELSE
L0(0):=ROUND(6371*π/180*Dist,-3)+" km "+IFTE(FUNCDMTODEG(L9(0))-PublLon>=0,ROUND(θ,0),ROUND(360-θ,0))+"°";
END;
END;
END;
END;
END;