(*****************************************************************************)
(* Acechan -- Produces data files which contain random data spread info.     *)
(* (c)1995 Lee "Wangi" Kindness                                              *)
(*****************************************************************************)
Program Acechan;

Uses
	Exec, AmigaDos, Amiga;

Const
	{ Version string }
	VERSTAG : String[31] = '$VER: Acechan 1.1 (26.04.95)'#13#10#0;

Type
	tConfig = Record
		cf_Outfile    : String; { name of file to output to          }
		cf_Min,                 { minimum value of range             }
		cf_Max,                 { maximum value in range             }
		cf_Iterations,          { number of iterations               }
		cf_dp         : LONG;   { number of decimal places in output }
		cf_RawOnly    : Boolean;{ do the graphical representation?   }
	End;

(*****************************************************************************)
Function GetInput(VAR cfg : tConfig) : Boolean;
{ Get options from the command line, using Amiga functions }

Const
	TEMP : String[61] = 'MINIMUM/N,MAXIMUM/N,ITERATIONS/N,DP/K/N,RAWONLY/S,OUTPUTFILE'#0;
	OPT_MIN   = 0; { minimum value of range             }
	OPT_MAX   = 1; { maximum value in range             }
	OPT_ITER  = 2; { number of iterations               }
	OPT_DP    = 3; { number of decimal places in output }
	OPT_RAW   = 4;
	OPT_FILE  = 5; { name of file to output to          }
	rda : Array[OPT_MIN..OPT_FILE] Of Pointer = (NIL,NIL,NIL,NIL,NIL);

Var
	RDArgs : pRDArgs;

Begin
	GetInput := False;
	{ init cfg to defaults }
	With cfg do Begin
		cf_Min        := 1;
		cf_Max        := 100;
		cf_Iterations := 1000;
		cf_dp         := 4;
		cf_Outfile    := 'acechan.results';
		cf_RawOnly    := False;
	End;
	RDArgs := ReadArgs(@TEMP[1], @rda, NIL);
	If RDArgs <> NIL Then Begin
		If rda[OPT_MIN] <> NIL Then
			cfg.cf_Min := pLONG(rda[OPT_MIN])^;
		If rda[OPT_MAX] <> NIL Then
			cfg.cf_Max := pLONG(rda[OPT_MAX])^;
		If rda[OPT_ITER] <> NIL Then
			cfg.cf_Iterations := pLONG(rda[OPT_ITER])^;
		If cfg.cf_Iterations < 10 Then
			cfg.cf_Iterations := 10;
		If rda[OPT_DP] <> NIL Then
			cfg.cf_dp := pLONG(rda[OPT_DP])^;
		If rda[OPT_RAW] <> NIL Then
			cfg.cf_RawOnly := True;
		If rda[OPT_FILE] <> NIL then
			cfg.cf_Outfile := PtrToPas(rda[OPT_FILE]);
		FreeArgs(RDArgs);
		GetInput := True;
	End;
End;

(*****************************************************************************)
Procedure DoIt(VAR cfg : tConfig);

(*****************)
(*
 * Set of functions to handle the 'array' type memory heap
 * quite a lot of dodgy programming here :)
 * If you are not an Amiga programmer then this might help:
 *  LONG = LongInt;
 *  pLONG = ^LONG;
 *  AllocVec allocates memory from the system, MENF_CLEAR specifying that
 *  it should be initilised to zeros, FreeVec will free this memory. I used
 *  Amiga kernal functions rather than portable pascal ones because the pascal
 *  ones use heap space...:(
 *)

Function AllocBuf : pLONG;
Begin
	AllocBuf := AllocVec((Sizeof(LONG) * (cfg.cf_Max - cfg.cf_Min + 1)), MEMF_CLEAR);
	(*
	 * Using standard pascal functions:
	 *
	 * VAR
	 *   p, e : pLONG;
	 *   n    : LONG;
	 *
	 * GetMem(p, (Sizeof(LONG) * (cfg.cf_Max - cfg.cf_Min + 1)));
	 * If p <> NIL Then Begin
	 *   For n := min to max Do Begin 
	 *     e := pLONG(LONG(buf) + ((n - cfg.cf_Min) * Sizeof(LONG)));
	 *     e^ := 0;
	 *   End;
	 * End;
	 * AllocBuf := p;
	 *)
End;

Procedure FreeBuf(buf : pLONG);
Begin
	FreeVec(buf);
	(*
	 * Using standard pascal functions:
	 *
	 * FreeMem(buf, (Sizeof(LONG) * (cfg.cf_Max - cfg.cf_Min + 1)));
	 *)
End;

Procedure IncBuf(buf : pLONG; entry : LONG);
Var
	e : pLONG;
Begin
	e := pLONG(LONG(buf) + ((entry - cfg.cf_Min) * Sizeof(LONG)));
	inc(e^);
End;

Function AccessBuf(buf : pLONG; entry : LONG) : LONG;
Var
	e : pLONG;
Begin
	e := pLONG(LONG(buf) + ((entry - cfg.cf_Min) * Sizeof(LONG)));
	AccessBuf := e^;
End;

Function RandRange(min, max : LONG) : LONG;
Begin
	RandRange := Random(max - min + 1) + min;
End;
	
(*****************)

Var
	buf : pLONG;
	n, num, y : LONG;
	f : Text;
	
Begin
	Randomize;
	With cfg Do Begin
		buf := AllocBuf;
		If buf <> NIL Then begin
			{ generate the random spread }
			For n := 1 To cf_Iterations do Begin
				num := RandRange(cf_Min, cf_Max);
				IncBuf(buf, num);
			End;
			{ create the output file }
			{ Assign(f, cf_OutFile); }
			{$I-} ReWrite(f, cf_Outfile); {$I+}
			If IOResult = 0 Then Begin
				Writeln(f, 'data results file created by Acechan, ŠLee Kindness');
				{ the raw data }
				Writeln(f);
				Writeln(f, 'RAW DATA:');
				Writeln(f);
				For n := cf_Min to cf_Max do
					Writeln(f, n:5,' : ',AccessBuf(buf, n):5,', ',((AccessBuf(buf, n)/cf_Iterations)*100):0:cf_dp,'%');
				If NOT cf_RawOnly Then Begin
					{ the distribution 'curve' }
					Writeln(f);
					Writeln(f, 'DISTRIBUTED REPRESENTATION');
					Writeln(f);
					For n := cf_Min to cf_Max do Begin
						Write(f, n:5,' ');
						num := AccessBuf(buf, n);
						for y := 1 to num Do
							Write(f, '#');
						Writeln(f, '  ',num,' ',((AccessBuf(buf, n)/cf_Iterations)*100):0:cf_dp,'%');
					End;
				End;
				Writeln('Finished!!');
				Close(f);
			End;
			FreeBuf(buf);
		End;
	End;
End;

(*****************************************************************************)
Procedure Main;

Var
	cfg : tConfig;

Begin
	If pLibrary(SysBase)^.lib_Version >= 36 Then Begin
		If pLibrary(DosBase)^.lib_Version >= 36 Then Begin
			If GetInput(cfg) Then Begin
				DoIt(cfg);
			End;
		End Else Writeln('This program requires dos.library 36 (2.0)');
	End Else Writeln('This program requires exec.library 36 (2.0)');
End;

(*****************************************************************************)
Begin main End.

(*****************************************************************************)