#!/bin/sh

# #!/usr/local/bin/dash
# #!/bin/dash
# #!/bin/ksh
#
# Fully POSIX random number generator for input numbers 2 to 1000.
#
# Wichmann-Hill method using 32 bit integer arithmetic.
# https://en.wikipedia.org/wiki/Wichmann%E2%80%93Hill
#
# This version is for the Classic AMIGA and ADE, the *NIX _emulator_ and 'KSH88' run as 'sh'.
# WH_RANDOM.sh

# Initialise variables as global.
EPOCH=1234567890.987654
SEED1=1
SEED2=1
SEED3=1
RAND_VAL=0.0
WH_RANDOM=0
TEST_NUM=256

# Get epoch value to microseonds.
if [ ! -f /tmp/epoch_microsecs ]
then
cat << 'EPOCH_MICROSECS' > /tmp/epoch_microsecs.c
/* 'epoch_microsecs.c' */

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

int main(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	printf("%ld.%06ld", tv.tv_sec, tv.tv_usec);
	exit(0);
}

EPOCH_MICROSECS
# Compile the above using gcc.
echo ''
echo 'Compiling "epoch_microsecs", please wait...'
gcc -Wall -pedantic -ansi -o /tmp/epoch_microsecs /tmp/epoch_microsecs.c -lm
echo 'Done!'
echo ''
fi

# Use clock timer for seeds.
time_seeds()
{
	# Create the three required seeds using the clock.
	# Each must be between 1 and 300 inclusive.
	EPOCH=$( /tmp/epoch_microsecs )
	SEED1=${EPOCH#??????????????}
	SEED1=$( expr ${SEED1} + 1 )
	if [ ${SEED1} -gt 300 ]
	then
		SEED1=$(( SEED1 / 4 ))
	fi
	#
	EPOCH=$( /tmp/epoch_microsecs )
	SEED2=${EPOCH#??????????????}
	SEED2=$( expr ${SEED2} + 1 )
	if [ ${SEED2} -gt 300 ]
	then
		SEED2=$(( SEED2 / 4 ))
	fi
	#
	EPOCH=$( /tmp/epoch_microsecs )
	SEED3=${EPOCH#??????????????}
	SEED3=$( expr ${SEED3} + 1 )
	if [ ${SEED3} -gt 300 ]
	then
		SEED3=$(( SEED3 / 4 ))
	fi
}

# Use user defined values for seeds.
fixed_seeds()
{
	# All seeds must be an integer, 1 to 300!
	# Called as 'fixed_seeds <SEED1> <SEED2> <SEED3><CR>'
	SEED1=${1}
	SEED2=${2}
	SEED3=${3}
	check_seeds
}

# Use external user defined values for seeds. 
manual_seeds()
{
	# All seeds must be an integer, 1 to 300!
	printf "Enter first integer seed, 1 to 300:- "
	read -r SEED1
	printf "Enter second integer seed, 1 to 300:- "
	read -r SEED2
	printf "Enter third integer seed, 1 to 300:- "
	read -r SEED3
	check_seeds
}

# Check user seeds for basic errors.
# Any other errors are taken care of by the shell itself.
check_seeds()
{
	if [ "${SEED1}" = "" ] || [ "${SEED2}" = "" ] || [ ${SEED3} = "" ]
	then
		echo "Usage1: fixed_seeds <SEED1> <SEED2> <SEED3>"
		echo "OR..."
		echo "Usage2: manual_seeds and then follow the on screen prompts!"
		echo "Aborting..."
		exit 1
	fi
	if [ ${SEED1} -lt 1 ] || [ ${SEED2} -lt 1 ] || [ ${SEED3} -lt 1 ]
	then
		echo "ERROR! One or more of the seeds are wrong! Aborting..."
		exit 2
	fi
	if [ ${SEED1} -gt 300 ] || [ ${SEED2} -gt 300 ] || [ ${SEED3} -gt 300 ]
	then
		echo "ERROR! One or more of the seeds are wrong! Aborting..."
		exit 3
	fi
}

# This is the working part of this Wichmann-Hill random module...
whrandom()
{
	SEED1=$(( ( 171 * SEED1 ) % 30269 ))
	SEED2=$(( ( 172 * SEED2 ) % 30307 ))
	SEED3=$(( ( 170 * SEED3 ) % 30323 ))

	RAND_VAL=$(( ( ( ( SEED1 * 1000 ) / 30269 ) + ( ( SEED2 * 1000 ) / 30307 ) + ( ( SEED3 * 1000 ) / 30323 ) ) % 1000 ))

	# Global 'RAND_VAL' displays as 0.000 to 0.999
	RAND_VAL=$( printf "%0.3f" "${RAND_VAL}e-3" )
}

# Test loop only, press Ctrl-C to stop...
test()
{
	while true
	do
		# Call 'whrandom' function...
		whrandom
		# Remove front '0.' first and any leading zeros, (0), after.
		RAND_VAL=$( expr ${RAND_VAL#??} + 0 )
		# Give a test number, 256 for this DEMO so as to have 0 to 255 values.
		TEST_NUM=256
		# Multiply the two integer variables together and integer division by 1000.
		WH_RANDOM=$(( ( RAND_VAL * TEST_NUM ) / 1000 ))
		echo "${WH_RANDOM}"
	done
}

time_seeds

test