Pollard Cubic Integer Factoring and Classical Shor Factoring Algorithms by James Pate Williams, Jr.

Back on Thursday, January 10, 2019, at 02:40 AM I started implementing J. M. Pollard’s factoring with cubic integers method and a classical variant of Shor’s quantum computer factoring algorithm. I have probably implemented at least three versions of Pollard’s magnificent work which led to the special number field sieve fast factoring method. I am working on translating my C# code of these two algorithms to Arjen K. Lenstra’s Free Large Integer Package in the C computer programming language. Appended to this electronic missive are factorizations of two small 19-decimal digit numbers 2^63-1 and 2^63+1. Pollard’s method requires that the exponent be divisible by three. Thus, we write the numbers as 2^ (21 * 3) plus or minus 1. You can factor numbers with different bases and small addends and subtrahends as long as the exponent is zero modulo 3. You will notice that Shor’s algorithm is very fast on these small numbers.

Pollard’s Factoring with Cubic Integers 2^63-1
Shor’s Classical Factoring of 2^63-1
Pollard’s Factoring with Cubic Integers 2^63+1
Shor’s Classical Factoring of 2^63+1

Three Factoring Algorithms Implemented Using the C Free Large Integer Package (Free LIP) by James Pate Williams, Jr.

This set of experiments is dedicated to Alfred J. Menezes, Arjen K. Lenstra, H. W. Lenstra, Jr., J. M. Pollard, Henri Cohen, Hans Riesel, H. T. Lau, Charles Petzold, Richard O. Chapman, Gerry V. Dozier, Homer Carlisle, Fay A. Riddle, Brooks Shelhorse, among many others whose names have faded from my memory.

The factoring algorithms are trial division, Brent’s modification of the famous Pollard rho Method, and Lenstra’s Elliptic Curve Method. I used repetitions of the digit string “1234567890” of varying length. I chose these strings because of the richness of prime factors.

These algorithms are not guaranteed to completely factor these relatively large numbers. I gave up on using the elliptic curve method for numbers of greater than 40-digits. I have to give up on Brent’s modification of the Pollard rho method for numbers of more than 70-digits.

Trial Division 30-Digit Number
Brent 30-Digit Number

ECM 30-Digit Number

Trial Division 40-Digit Number

Brent 40-Digit Number

ECM 40-Digit Number

Trial Division 50-Digit Number Missing Two or More Prime Factors

Brent 50-Digit Number

Trial Division 60-Digit Number

Brent 60-Digit Number

Trial Division 70-Digit Number

Brent 70-Digit Number

Trial Division 80-Digit Number

Trial Division 90-Digit Number

Trial Division 100-Digit Number
/*
Author:  Pate Williams (c) 1997 - 2022

Algorithm 8.5.2 (Pollard rho). See "A Course in
Computational Algebraic Number Theory" by Henri
Cohen page 429.

Author:  Pate Williams (c) 1997 - 2022

Algorithm 10.3.3 (Lenstra's ECM). See "A Course
in Computational Algebraic Number Theory" by
Henri Cohen page 488.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lip.h"

typedef struct fact {
	verylong zf;
	int expon;
} FACTOR, PFACTOR;

int BOUND = 100000000;

void add_factor(int e, verylong zp,
	FACTOR f[], int *count)
{
	int done = 0, found = 0, i, j = 0;

	for (i = 0; !done && i < *count; i++)
	{
		found = zcompare(zp, f[i].zf);

		if (found == 0)
		{
			done = 1;
			j = i;
		}
	}

	if (found == 0)
	{
		for (i = *count - 2; i >= j; i--)
		{
			f[i + 1].expon = f[i].expon;
			zcopy(f[i].zf, &f[i + 1].zf);
		}

		*count = *count + 1;
		f[j].expon = e;
		
		zcopy(zp, &f[j].zf);
	}
	
	else if (found == 0) 
		f[j].expon++;
	
	else
	{
		f[*count].expon = e;
		zcopy(zp, &f[*count].zf);
		*count = *count + 1;
	}
}

int trial_division(verylong *zN, FACTOR f[], int *count)
{
	int e, one = 0, pr = 0;
	long B, p;
	verylong za = 0, zb = 0, zp = 0;

	zsqrt(*zN, &za, &zb);
	
	if (zscompare(za, BOUND) > 0)
		B = BOUND;
	
	else 
		B = ztoint(za);

	zcopy(*zN, &za);
	zpstart2();
	
	do {
		p = zpnext();

		if (zsmod(za, p) == 0)
		{
			e = 0;
			
			do {
				zsdiv(za, p, &zb);
				zcopy(zb, &za);
				e++;
			} while (zsmod(za, p) == 0);
		
			zintoz(p, &zp);
			add_factor(e, zp, f, count);
			zcopy(za, zN);
			one = zscompare(*zN, 1l) == 0;

			if (!one)
				pr = zprobprime(*zN, 5l);
		}
	} while (!one && !pr && p <= B);

	if (pr)
		add_factor(1, *zN, f, count);
	
	zfree(&za);
	zfree(&zb);
	zfree(&zp);

	return p <= B;
}

void Brent(verylong *zN, FACTOR f[], int *count)
{
	int e, one, pr;
	long c, i, k, l;
	verylong zP = 0, za = 0, zb = 0, zg = 0, zn = 0;
	verylong zx = 0, zx1 = 0, zy = 0;

	zcopy(*zN, &zn);

	do {
		c = 0, k = l = 1;
		zone(&zP);
		zintoz(2l, &zy);
		zintoz(2l, &zx);
		zintoz(2l, &zx1);
	L2:
		zsq(zx, &za);
		zsadd(za, 1l, &zb);
		zmod(zb, zn, &zx);
		zsub(zx1, zx, &za);
		zmulmod(za, zP, zn, &zb);
		zcopy(zb, &zP);

		if (++c == 20) {
			zgcd(zP, zn, &zg);
			if (zscompare(zg, 1l) > 0) goto L4;
			zcopy(zx, &zy);
			c = 0;
		}

		if (--k != 0)
			goto L2;
		
		zgcd(zP, zn, &zg);
		
		if (zscompare(zg, 1l) > 0)
			goto L4;
		
		zcopy(zx, &zx1);
		k = l, l *= 2;
		
		for (i = 0; i < k; i++)
		{
			zsq(zx, &za);
			zsadd(za, 1l, &zb);
			zmod(zb, zn, &zx);
		}

		zcopy(zx, &zy);
		c = 0;
		
		goto L2;
	L4:
		do {
			zsq(zy, &za);
			zsadd(za, 1l, &zb);
			zmod(zb, zn, &zy);
			zsub(zx1, zy, &za);
			zgcd(za, zn, &zg);
		} while (zscompare(zg, 1l) == 0);

		if (zcompare(zg, zn) == 0) {
			fprintf(stderr, "fatal error\nBrent's method failed\n");
			exit(1);
		}

		if (!zprobprime(zg, 20l))
		{
			zcopy(zg, &za);
		
			if (!trial_division(&zg, f, count)) {
				fprintf(stderr, "fatal error\ncould not trial divide\n");
				exit(1);
			}

			zcopy(za, &zg);
			zdiv(zn, zg, &za, &zb);
			zcopy(za, &zn);
		}
		else
		{
			e = 0;
			
			do {
				zdiv(zn, zg, &za, &zb);
				zcopy(za, &zn);
				zmod(zn, zg, &za);
				e++;
			} while (zscompare(za, 0l) == 0);

			add_factor(e, zg, f, count);
		}
		one = zscompare(zn, 1l) == 0;
		if (!one) pr = zprobprime(zn, 5l);
	} while (!one && !pr);

	if (!one)
		add_factor(1, zn, f, count);

	zfree(&zP);
	zfree(&za);
	zfree(&zb);
	zfree(&zg);
	zfree(&zn);
	zfree(&zx);
	zfree(&zx1);
	zfree(&zy);
}

int partition(FACTOR a[], int n, int lo, int hi)
{
	int pivotIndex = lo + (hi - lo) / 2;
	FACTOR x = a[pivotIndex];
	FACTOR t = x;

	a[pivotIndex] = a[hi];
	a[hi] = t;

	int storeIndex = lo;

	for (int i = lo; i < hi; i++)
	{
		if (zcompare(a[i].zf, x.zf) < 0)
		{
			t = a[i];
			a[i] = a[storeIndex];
			a[storeIndex++] = t;
		}
	}

	t = a[storeIndex];
	a[storeIndex] = a[hi];
	a[hi] = t;

	return storeIndex;
}

void do_quick_sort(FACTOR a[], int n, int p, int r)
{
	if (p < r)
	{
		int q = partition(a, n, p, r);

		do_quick_sort(a, n, p, q - 1);
		do_quick_sort(a, n, q + 1, r);
	}
}

void quick_sort(FACTOR a[], int n)
{
	do_quick_sort(a, n, 0, n - 1);
}

#ifndef CLK_TCK
#define CLK_TCK CLOCKS_PER_SEC
#endif
#define CURVES 1024l

struct point { verylong zx, zy, zz; };
struct factor { int expon; verylong prime; };

static char cexp[32][32], cfac[32][512];
static int cnt, primeCount;

int partial_addition(verylong za,
	verylong zn,
struct point P,
struct point Q,
struct point *R,
	verylong *zd)
	/* returns 0 if sum is found or 1 if divisor is found */
{
	int value = 0;
	verylong zb = 0, zc = 0, zl = 0, zs = 0, zt = 0;
	verylong zx = 0, zy = 0, zy2 = 0;

	if (zcompare(P.zx, Q.zx) == 0 &&
		zscompare(P.zy, 0l) == 0 &&
		zscompare(Q.zy, 0l) == 0) {
		zzero(&R->zx);
		zone(&R->zy);
		return 0;
	}

	zsub(zn, Q.zy, &zb);

	if (zcompare(P.zx, Q.zx) == 0 &&
		zcompare(P.zy, zb) == 0) {
		zzero(&R->zx);
		zone(&R->zy);
		zfree(&zb);
		return 0;
	}

	if (zscompare(P.zx, 0l) == 0 &&
		zscompare(P.zy, 1l) == 0 &&
		zscompare(P.zz, 0l) == 0) {

		/* O + Q = Q */

		zcopy(Q.zx, &R->zx);
		zcopy(Q.zy, &R->zy);
		zcopy(Q.zz, &R->zz);
		value = 0;
	}

	else if (zscompare(Q.zx, 0l) == 0 &&
		zscompare(Q.zy, 1l) == 0 &&
		zscompare(Q.zz, 0l) == 0) {

		/* P + O = P */

		zcopy(P.zx, &R->zx);
		zcopy(P.zy, &R->zy);
		zcopy(P.zz, &R->zz);
		value = 0;
	}

	else {

		/* P != O and Q != O */

		zcopy(Q.zy, &zy2);
		znegate(&zy2);
		if (zcompare(P.zx, Q.zx) == 0 &&
			zcompare(P.zy, zy2) == 0) {
			zzero(&R->zx);
			zone(&R->zy);
			zzero(&R->zz);
		}

		else {
			if (zcompare(P.zx, Q.zx) != 0) {
				zsubmod(P.zx, Q.zx, zn, &zx);
				zexteucl(zx, &zs, zn, &zt, zd);
				if (zscompare(*zd, 1l) != 0) goto L1;
				zsubmod(P.zy, Q.zy, zn, &zy);
				zmulmod(zs, zy, zn, &zl);
			}

			else {
				zaddmod(P.zy, Q.zy, zn, &zy);
				zexteucl(zy, &zs, zn, &zt, zd);
				if (zscompare(*zd, 1l) != 0) goto L1;
				zmulmod(P.zx, P.zx, zn, &zb);
				zsmulmod(zb, 3l, zn, &zc);
				zaddmod(zc, za, zn, &zb);
				zmulmod(zs, zb, zn, &zl);
			}

			zmulmod(zl, zl, zn, &zb);
			zaddmod(P.zx, Q.zx, zn, &zc);
			zsubmod(zb, zc, zn, &zx);
			zcopy(zx, &R->zx);
			zsubmod(zx, P.zx, zn, &zb);
			zmulmod(zl, zb, zn, &zc);
			zaddmod(zc, P.zy, zn, &zy);
			znegate(&zy);
			zcopy(zy, &R->zy);
			zone(&R->zz);
			goto L2;
		L1:
			value = 1;
		L2:
			;
		}
	}
	zfree(&zb);
	zfree(&zc);
	zfree(&zl);
	zfree(&zs);
	zfree(&zt);
	zfree(&zx);
	zfree(&zy);
	zfree(&zy2);
	return value;
}

int multiply(long k,
	verylong za,
	verylong zn,
struct point P,
struct point *R,
	verylong *zd)
{
	int value = 0;
	struct point A, S, T;

	A.zx = A.zy = A.zz = S.
		zx = S.zy = S.zz = 0;
	T.zx = T.zy = T.zz = 0;

	zzero(&R->zx);
	zone(&R->zy);
	zzero(&R->zz);
	zcopy(P.zx, &S.zx);
	zcopy(P.zy, &S.zy);
	zcopy(P.zz, &S.zz);

	while (!value && k != 0) {
		if (k & 1) {
			value = partial_addition(za, zn, *R, S, &A, zd);
			zcopy(A.zx, &R->zx);
			zcopy(A.zy, &R->zy);
			zcopy(A.zz, &R->zz);
		}

		k >>= 1;

		if (!value && k != 0) {
			value = partial_addition(za, zn, S, S, &T, zd);
			zcopy(T.zx, &S.zx);
			zcopy(T.zy, &S.zy);
			zcopy(T.zz, &S.zz);
		}
	}

	if (zscompare(R->zy, 0l) < 0) {
		zadd(R->zy, zn, &A.zy);
		zcopy(A.zy, &R->zy);
	}

	zfree(&A.zx);
	zfree(&A.zy);
	zfree(&A.zz);
	zfree(&S.zx);
	zfree(&S.zy);
	zfree(&S.zz);
	zfree(&T.zx);
	zfree(&T.zy);
	zfree(&T.zz);
	return value;
}

/* the following definition limits the L3 loop */

int LenstrasECM(verylong *zN, verylong *zg)
{
	int expon = 0, found = 0;
	long B = 2000000l, i, j, k = 0, l, *p, q, q1;
	long giveUp = z2log(*zN);
	struct point x, y;
	verylong za[CURVES], zb = 0, zd = 0;

	for (i = 0; i < CURVES; i++)
		za[i] = 0;

	x.zx = x.zy = x.zz = y.zx = y.zy = y.zz = 0;

	zpstart2();

	do {
		q = zpnext();
		k++;
	} while (q < B);

	p = calloc(k, sizeof(long));

	if (!p) {
		expon = -1;
		goto L4;
	}

	zpstart2();

	for (i = 0; i < k; i++)
		p[i] = zpnext();

	for (i = 0; i < CURVES; i++)
		zrandomb(*zN, &za[i]);

L2:

	zone(&x.zx);
	zone(&x.zy);
	zzero(&x.zz);
	i = -1;

L3:

	i++;

	if (i == giveUp) {
		expon = 0;
		goto L4;
	}

	if (i == k) {

		for (i = 0; i < CURVES; i++)
			zrandomb(*zN, &za[i]);

		goto L2;
	}

	q = p[i];
	q1 = q;
	l = B / q;

	while (q1 <= l)
		q1 *= q;

	found = 0;

	for (j = 0; !found && j < CURVES; j++)
		found = multiply(q1, za[j], *zN, x, &y, &zd);

	if (!found)
		goto L3;

	zcopy(y.zx, &x.zx);
	zcopy(y.zy, &x.zy);
	zcopy(y.zz, &x.zz);
	zgcd(zd, *zN, zg);

	if (zcompare(*zg, *zN) == 0) {
		for (j = 0; j < CURVES; j++)
			zrandomb(*zN, &za[j]);

		goto L2;
	}

	if (!zprobprime(*zg, 5l))
		goto L4;

	expon = 0;

	do {
		zdiv(*zN, *zg, &zb, &zd);
		zcopy(zb, zN);
		zmod(*zN, *zg, &zd);
		expon++;
	} while (zscompare(zd, 0l) == 0);

L4:

	for (i = 0; i < CURVES; i++)
		zfree(&za[i]);

	zfree(&zb);
	zfree(&zd);
	zfree(&x.zx);
	zfree(&x.zy);
	zfree(&x.zz);
	zfree(&y.zx);
	zfree(&y.zy);
	zfree(&y.zz);
	return expon;
}

int ECMVLConvert(verylong zx, char *str, int length)
{
	verylong zy = 0;
	int a, result = 1, i = 0;

	while (zscompare(zx, 0) > 0)
	{
		zsdiv(zx, 10, &zy);
		a = zsmod(zx, 10);
		zcopy(zy, &zx);

		if (i < length)
			str[i++] = a + '0';

		else
		{
			result = 0;
			break;
		}
	}

	str[i] = '\0';
	
	_strrev(str);

	zfree(&zy);
	return result;
}

int ECMLast(char exp[32][32], char fac[32][512], struct factor *f, int *cnt)
{
	int i;

	for (i = 0; i < *cnt; i++)
	{
		if (ECMVLConvert(f[i].prime, fac[i], 512) == 1)
			sprintf(exp[i], "%d", f[i].expon);

		else
			return 0;
	}

	return 1;
}

int DoECM(char exp[32][32], char fac[32][512], char *numStr,
	int *cnt, int base, int iExpon, int addend)
{
	struct factor f[32];
	int i, j, result;
	int cant, expon, one, pri;
	verylong zn = 0, zN = 0, zd = 0, zg = 0;

	if (strlen(numStr) != 0)
		zstrtoz(numStr, &zN);

	else
	{
		static verylong zb = 0, zp = 0;

		zintoz(base, &zb);

		zsexp(zb, iExpon, &zp);
		zsadd(zp, addend, &zN);
	}

	zcopy(zN, &zn);

	for (i = 0; i < 32; i++)
	{
		f[i].expon = 0;
		f[i].prime = 0;
	}

	*cnt = 0;

	f[*cnt].expon = 1;
	zcopy(zN, &f[*cnt].prime);
	*cnt = *cnt + 1;

	if (z2log(zn) > 512)
	{
		result = 3;
		goto L1;
	}

	if (zprobprime(zN, 5l))
	{
		result = 2;
		goto L1;
	}

	cant = pri = 0;

	do {
		expon = LenstrasECM(&zN, &zg);

		if (expon == -1)
		{
			result = -1;
			goto L1;
		}

		if (zprobprime(zg, 5l))
		{
			f[*cnt].expon = expon;
			zcopy(zg, &f[*cnt].prime);
			*cnt = *cnt + 1;
		}

		one = zscompare(zN, 1l) == 0;

		if (zprobprime(zN, 5l))
		{
			f[*cnt].expon = 1;
			zcopy(zN, &f[*cnt].prime);
			*cnt = *cnt + 1;
			break;
		}

	} while (!one);

	/* selection sort the factors */

	for (i = 1; i < *cnt - 1; i++)
	{
		for (j = i + 1; j < *cnt; j++)
		{
			if (zcompare(f[i].prime, f[j].prime) > 0)
			{
				int temp;
				verylong zt = 0;

				zcopy(f[i].prime, &zt);
				zcopy(f[j].prime, &f[i].prime);
				zcopy(zt, &f[j].prime);

				temp = f[i].expon;
				f[i].expon = f[j].expon;
				f[j].expon = temp;
			}
		}
	}

	result = ECMLast(exp, fac, f, cnt);

L1:

	if (result == 2)
	{
		int temp = ECMLast(exp, fac, f, cnt);

		if (temp == 0)
			result = 3;
	}

	zfree(&zn);
	zfree(&zN);
	zfree(&zd);
	zfree(&zg);

	return result;
}

int PrimeCheck(char fac[32][512], int cnt)
{
	int i, result = 0;
	verylong zp = 0;

	for (i = 0; i < cnt; i++)
	{
		zstrtoz(fac[i], &zp);

		if (zprobprime(zp, 20l))
			result++;
	}

	return result;
}

int ECMMethod(char *numStr, int base, int expon, int addend)
{
	int i, result;

	cnt = 0;

	for (i = 0; i < 32; i++)
	{
		cexp[i][0] = '\0';
		cfac[i][0] = '\0';
	}

	result = DoECM(cexp, cfac, numStr, &cnt, base, expon, addend);
	primeCount = PrimeCheck(cfac, cnt);

	return result;
}

int main()
{
	int i = 0, zacount = 0;
	verylong zN = 0, zf = 0, zn = 0, zo = 0;
	verylong zq = 0, zr = 0, zs = 0;
	FACTOR za[32] = { 0 };

	zintoz(1, &zo);

	while (1) {
		clock_t time0;
		char numStr[256] = { 0 }, option[256] = { 0 }, *bPtr, *ePtr;
		double time;
		int c, base, expon, addend, iExpon = 0, positive, result;

		printf("Menu\n");
		printf("1 Trial Division\n");
		printf("2 Pollard rho\n");
		printf("3 Lenstra's Elliptic Curve Method\n");
		printf("4 Exit\n");
		printf("Enter choice (1 - 4): ");

		c = getchar();
		i = 0;

		while (c != '\n' && i < 256)
		{
			option[i++] = c;
			c = getchar();
		}

		option[i] = '\0';

		if (option[0] == '4')
			break;

		if (option[0] < '1' || option[0] > '3')
		{
			printf("Unknown choice, please reenter choice\n");
			continue;
		}

		printf("enter the number below (0 to quit):\n");

		i = 0;
		c = getchar();

		while (c != '\n' && i < 256)
		{
			numStr[i++] = c;
			c = getchar();
		}

		numStr[i] = '\0';

		bPtr = strchr(numStr, '^');

		if (bPtr != NULL)
		{
			*bPtr = '\0';
			base = atoi(numStr);
			ePtr = strchr(bPtr + 1, '+');

			if (ePtr != NULL)
				positive = 1;

			else
			{
				ePtr = strchr(bPtr + 1, '-');

				if (ePtr != NULL)
					positive = 0;
			}

			if (ePtr != NULL)
				*ePtr = '\0';

			expon = atoi(bPtr + 1);

			if (ePtr != NULL) {
				addend = atoi(ePtr + 1);

				if (positive == 0)
					addend = -addend;
			}

			else
				addend = 0;

			numStr[0] = '\0';
		}

		else
		{
			addend = atoi(numStr);

			if (addend == 0)
				break;
		}

		if (strlen(numStr) != 0)
			zstrtoz(numStr, &zN);

		else
		{
			static verylong zb = 0, zp = 0;

			zintoz(base, &zb);

			zsexp(zb, iExpon, &zp);
			zsadd(zp, addend, &zN);
		}

		zcopy(zN, &zn);

		if (zmcomposite(zn, 20) == 0)
		{
			printf("Number is prime\n");
			continue;
		}

		zacount = 0;

		for (i = 0; i < 32; i++)
		{
			if (za[i].zf != 0)
				zfree(&za[i].zf);

			za[i].expon = 0;
		}
		time0 = clock();

		if (option[0] == '1')
		{
			printf("Trial division factors:\n");
			trial_division(&zN, za, &zacount);
		}

		else if (option[0] == '2')
		{
			printf("Pollard rho factors:\n");
			Brent(&zN, za, &zacount);
		}

		else if (option[0] == '3')
		{
			printf("Lenstra's ECM factors:\n");
			result = ECMMethod(numStr, base, expon, addend);

			if (result == 0)
				printf("can't completely factor this number\n");

			else if (result == 1)
			{
				printf("%s\nnumber is composite factors:\n", cfac[0]);

				for (i = 1; i < cnt; i++)
					if (strcmp(cexp[i], "1") == 0)
						printf("\t%s\n", cfac[i]);
					else
						printf("\t%s ^ %s\n", cfac[i], cexp[i]);
			}

			else if (result == 2)
				printf("%s\nnumber is prime:\n", cfac[0]);

			else if (result == 3)
				printf("number or prime factor is too large\n");
		}

		if (option[0] < '3' && zacount > 0)
		{
			quick_sort(za, zacount);

			for (i = 0; i < zacount; i++)
			{
				zwrite(za[i].zf);

				if (za[i].expon > 1)
					printf(" ^ %d ", za[i].expon);

				printf("\n");
			}

			for (i = 0; i < zacount; i++)
				if (za[i].zf != 0)
					zfree(&za[i].zf);
			
			zacount = 0;
		}

		time = (clock() - time0) / (double)CLK_TCK;
		printf("total time required: %f seconds\n", time);
	}

	zfree(&zN);
	zfree(&zn);
	zfree(&zf);
	zfree(&zo);
	zfree(&zq);
	zfree(&zr);
}

Lenstra’s Elliptic Curve Method of Factoring Large Integers Using the Free Large Integer Package (FreeLIP) by James Pate Williams, Jr.

Factoring a 35-Decimal Digit Number
Factoring a 40-Decimal Digit Number
/*
	Author:  Pate Williams (c) 1997 - 2009
	
	Algorithm 10.3.3 (Lenstra's ECM). See "A Course
	in Computational Algebraic Number Theory" by
	Henri Cohen page 488.
*/

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lip.h"

#ifndef CLK_TCK
#define CLK_TCK CLOCKS_PER_SEC
#endif

/*
	if you creating a Windows only program
	the following function can be edited
	out or completely removed since strrev
	is defined in Windows Visual Studio C
*/

char * strrev(char *s)
{
	int i, length = strlen(s), j = length - 1;
	char *t = malloc((length + 1) * sizeof(char));
	
	if (t == NULL)
		return NULL;

	for (i = 0; i < length; i++, j--)
		t[j] = s[i];
		
	t[length] = '\0';
	
	strcpy(s, t);
	free(t);
	
	return s;
}

#define CURVES 1024l

struct point {verylong zx, zy, zz;};
struct factor {int expon; verylong prime;};

static char cexp[32][32], cfac[32][512];
static int cnt, primeCount;

int partial_addition(verylong za,
					 verylong zn,
					 struct point P,
					 struct point Q,
					 struct point *R,
					 verylong *zd)

/* returns 0 if sum is found or 1 if divisor is found */

{
	int value = 0;
	verylong zb = 0, zc = 0, zl = 0, zs = 0, zt = 0;
	verylong zx = 0, zy = 0, zy2 = 0;
	
	if (zcompare(P.zx, Q.zx) == 0 &&
		zscompare(P.zy, 0l) == 0 &&
		zscompare(Q.zy, 0l) == 0) {
		zzero(&R->zx);
		zone(&R->zy);
		return 0;
	}

	zsub(zn, Q.zy, &zb);
	
	if (zcompare(P.zx, Q.zx) == 0 &&
		zcompare(P.zy, zb) == 0) {
		zzero(&R->zx);
		zone(&R->zy);
		zfree(&zb);
		return 0;
	}
	
	if (zscompare(P.zx, 0l) == 0 &&
		zscompare(P.zy, 1l) == 0 &&
		zscompare(P.zz, 0l) == 0) {
		
		/* O + Q = Q */
		
		zcopy(Q.zx, &R->zx);
		zcopy(Q.zy, &R->zy);
		zcopy(Q.zz, &R->zz);
		value = 0;
	}

	else if (zscompare(Q.zx, 0l) == 0 &&
		zscompare(Q.zy, 1l) == 0 &&
		zscompare(Q.zz, 0l) == 0) {

		/* P + O = P */
		
		zcopy(P.zx, &R->zx);
		zcopy(P.zy, &R->zy);
		zcopy(P.zz, &R->zz);
		value = 0;
	}

	else {
		
		/* P != O and Q != O */
		
		zcopy(Q.zy, &zy2);
		znegate(&zy2);
		if (zcompare(P.zx, Q.zx) == 0  &&
			zcompare(P.zy, zy2)  == 0) {
			zzero(&R->zx);
			zone(&R->zy);
			zzero(&R->zz);
		}

		else {
			if (zcompare(P.zx, Q.zx) != 0) {
				zsubmod(P.zx, Q.zx, zn, &zx);
				zexteucl(zx, &zs, zn, &zt, zd);
				if (zscompare(*zd, 1l) != 0) goto L1;
				zsubmod(P.zy, Q.zy, zn, &zy);
				zmulmod(zs, zy, zn, &zl);
			}

			else {
				zaddmod(P.zy, Q.zy, zn, &zy);
				zexteucl(zy, &zs, zn, &zt, zd);
				if (zscompare(*zd, 1l) != 0) goto L1;
				zmulmod(P.zx, P.zx, zn, &zb);
				zsmulmod(zb, 3l, zn, &zc);
				zaddmod(zc, za, zn, &zb);
				zmulmod(zs, zb, zn, &zl);
			}

			zmulmod(zl, zl, zn, &zb);
			zaddmod(P.zx, Q.zx, zn, &zc);
			zsubmod(zb, zc, zn, &zx);
			zcopy(zx, &R->zx);
			zsubmod(zx, P.zx, zn, &zb);
			zmulmod(zl, zb, zn, &zc);
			zaddmod(zc, P.zy, zn, &zy);
			znegate(&zy);
			zcopy(zy, &R->zy);
			zone(&R->zz);
			goto L2;
L1:
			value = 1;
L2:
			;
		}
	}
	zfree(&zb);
	zfree(&zc);
	zfree(&zl);
	zfree(&zs);
	zfree(&zt);
	zfree(&zx);
	zfree(&zy);
	zfree(&zy2);
	return value;
}

int multiply(long k,
			 verylong za,
			 verylong zn,
			 struct point P,
			 struct point *R,
			 verylong *zd)
{
	int value = 0;
	struct point A, S, T;
	
	A.zx = A.zy = A.zz = S.
	  zx = S.zy = S.zz = 0;
	T.zx = T.zy = T.zz = 0;

	zzero(&R->zx);
	zone(&R->zy);
	zzero(&R->zz);
	zcopy(P.zx, &S.zx);
	zcopy(P.zy, &S.zy);
	zcopy(P.zz, &S.zz);
	
	while (!value && k != 0) {
		if (k & 1) {
			value = partial_addition(za, zn, *R, S, &A, zd);
			zcopy(A.zx, &R->zx);
			zcopy(A.zy, &R->zy);
			zcopy(A.zz, &R->zz);
		}

		k >>= 1;
		
		if (!value && k != 0) {
			value = partial_addition(za, zn, S, S, &T, zd);
			zcopy(T.zx, &S.zx);
			zcopy(T.zy, &S.zy);
			zcopy(T.zz, &S.zz);
		}
	}

	if (zscompare(R->zy, 0l) < 0) {
		zadd(R->zy, zn, &A.zy);
		zcopy(A.zy, &R->zy);
	}

	zfree(&A.zx);
	zfree(&A.zy);
	zfree(&A.zz);
	zfree(&S.zx);
	zfree(&S.zy);
	zfree(&S.zz);
	zfree(&T.zx);
	zfree(&T.zy);
	zfree(&T.zz);
	return value;
}

/* the following definition limits the L3 loop */

int LenstrasECM(verylong *zN, verylong *zg)
{
	int expon = 0, found;
	long B = 2000000l, i, j, k = 0, l, *p, q, q1;
	long giveUp = z2log(*zN);
	struct point x, y;
	verylong za[CURVES], zb = 0, zd = 0;
	
	for (i = 0; i < CURVES; i++)
		za[i] = 0;
	
	x.zx = x.zy = x.zz = y.zx = y.zy = y.zz = 0;
	
	zpstart2();

	do {
		q = zpnext();
		k++;
	} while (q < B);
	
	p = calloc(k, sizeof(long));
	
	if (!p) {
		expon = - 1;
		goto L4;
	}
	
	zpstart2();
	
	for (i = 0; i < k; i++)
		p[i] = zpnext();
	
	for (i = 0; i < CURVES; i++)
		zrandomb(*zN, &za[i]);

L2:

	zone(&x.zx);
	zone(&x.zy);
	zzero(&x.zz);
	i = - 1;

L3:
	
	i++;
	
	if (i == giveUp) {
		expon = 0;
		goto L4;
	}
	
	if (i == k) {
	
		for (i = 0; i < CURVES; i++)
			zrandomb(*zN, &za[i]);

		goto L2;
	}

	q = p[i];
	q1 = q;
	l = B / q;
	
	while (q1 <= l)
		q1 *= q;
	
	found = 0;
	
	for (j = 0; !found && j < CURVES; j++)
		found = multiply(q1, za[j], *zN, x, &y, &zd);
	
	if (!found)
		goto L3;
	
	zcopy(y.zx, &x.zx);
	zcopy(y.zy, &x.zy);
	zcopy(y.zz, &x.zz);
	zgcd(zd, *zN, zg);

	if (zcompare(*zg, *zN) == 0) {
		for (j = 0; j < CURVES; j++)
			zrandomb(*zN, &za[j]);
	
		goto L2;
	}

	if (!zprobprime(*zg, 5l))
		goto L4;

	expon = 0;

	do {
		zdiv(*zN, *zg, &zb, &zd);
		zcopy(zb, zN);
		zmod(*zN, *zg, &zd);
		expon++;
	} while (zscompare(zd, 0l) == 0);

L4:
	
	for (i = 0; i < CURVES; i++)
		zfree(&za[i]);
	
	zfree(&zb);
	zfree(&zd);
	zfree(&x.zx);
	zfree(&x.zy);
	zfree(&x.zz);
	zfree(&y.zx);
	zfree(&y.zy);
	zfree(&y.zz);
	return expon;
}

int ECMVLConvert(verylong zx, char *str, int length)
{
	verylong zy = 0;
	int a, result = 1, i = 0;
	
	while (zscompare(zx, 0) > 0)
	{
		zsdiv(zx, 10, &zy);
		a = zsmod(zx, 10);
		zcopy(zy, &zx);
		
		if (i < length)
			str[i++] = a + '0';
		
		else
		{
			result = 0;
			break;
		}
	}
	
	str[i] = '\0';
	strrev(str);
	
	zfree(&zy);
	return result;
}

int ECMLast(char exp[32][32], char fac[32][512], struct factor *f, int *cnt)
{
	int i;
	
	for (i = 0; i < *cnt; i++)
	{
		if (ECMVLConvert(f[i].prime, fac[i], 512) == 1)
			sprintf(exp[i], "%d", f[i].expon);
		
		else
			return 0;
	}
	
	return 1;
}

int DoECM(char exp[32][32], char fac[32][512], char *numStr,
		  int *cnt, int base, int iExpon, int addend)
{
	struct factor f[32];
	int i, j, result;
	int cant, expon, one, pri;
	verylong zn = 0, zN = 0, zd = 0, zg = 0;
	
	if (strlen(numStr) != 0)
		zstrtoz(numStr, &zN);
	
	else
	{
		static verylong zb = 0, zp = 0;
		
		zintoz(base, &zb);
		
		zsexp(zb, iExpon, &zp);
		zsadd(zp, addend, &zN);
	}
	
	zcopy(zN, &zn);

	for (i = 0; i < 32; i++)
	{
		f[i].expon = 0;
		f[i].prime = 0;
	}
	
	*cnt = 0;
	
	f[*cnt].expon = 1;
	zcopy(zN, &f[*cnt].prime);
	*cnt = *cnt + 1;
	
	if (z2log(zn) > 512)
	{
		result = 3;
		goto L1;
	}
	
	if (zprobprime(zN, 5l))
	{
		result = 2;
		goto L1;
	}
	
	cant = pri = 0;
	
	do {

		expon = LenstrasECM(&zN, &zg);

		if (expon == - 1)
		{
			result = - 1;
			goto L1;
		}

		if (zprobprime(zg, 5l))
		{
			f[*cnt].expon = expon;
			zcopy(zg, &f[*cnt].prime);
			*cnt = *cnt + 1;
		}

		one = zscompare(zN, 1l) == 0;

		if (zprobprime(zN, 5l))
		{
			f[*cnt].expon = 1;
			zcopy(zN, &f[*cnt].prime);
			*cnt = *cnt + 1;
			break;
		}

	} while (!one);
	
	/* selection sort the factors */
	
	for (i = 1; i < *cnt - 1; i++)
	{
		for (j = i + 1; j < *cnt; j++)
		{
			if (zcompare(f[i].prime, f[j].prime) > 0)
			{
				int temp;
				verylong zt = 0;
					
				zcopy(f[i].prime, &zt);
				zcopy(f[j].prime, &f[i].prime);
				zcopy(zt, &f[j].prime);
				
				temp = f[i].expon;
				f[i].expon = f[j].expon;
				f[j].expon = temp;
			}
		}
	}

	result = ECMLast(exp, fac, f, cnt);

L1:

	if (result == 2)
	{
		int temp = ECMLast(exp, fac, f, cnt);
		
		if (temp == 0)
			result = 3;
	}
	
	zfree(&zn);
	zfree(&zN);
	zfree(&zd);
	zfree(&zg);

	return result;
}

int PrimeCheck(char fac[32][512], int cnt)
{
	int i, result = 0;
	verylong zp = 0;
	
	for (i = 0; i < cnt; i++)
	{	
		zstrtoz(fac[i], &zp);

		if (zprobprime(zp, 5l))
			result++;
	}

	return result;
}

int ECMMethod(char *numStr, int base, int expon, int addend)
{
	int i, result;
	
	cnt = 0;
	
	for (i = 0; i < 32; i++)
	{
		cexp[i][0] = '\0';
		cfac[i][0] = '\0';
	}
	
	result = DoECM(cexp, cfac, numStr, &cnt, base, expon, addend);
	
	primeCount = PrimeCheck(cfac, cnt);

	return result;
}

int main(int argc, char *argv[])
{
	while (1) {
		clock_t time0;
		char numStr[1024] = {0}, *bPtr, *ePtr;
		double time;
		int c, base, expon, addend, i = 0, positive, result;

		printf("enter the number below (0 to quit):\n");
		
		c = getchar();
		
		while (c != '\n' && i < 1023)
		{
			numStr[i++] = c;
			c = getchar();
		}
		
		numStr[i] = '\0';
		
		bPtr = strchr(numStr, '^');

		if (bPtr != NULL)
		{
			*bPtr = '\0';
			base = atoi(numStr);
			ePtr = strchr(bPtr + 1, '+');
			
			if (ePtr != NULL)
				positive = 1;

			else {
				ePtr = strchr(bPtr + 1, '-');
				
				if (ePtr != NULL)
					positive = 0;
			}

			if (ePtr != NULL)
				*ePtr = '\0';
			
			expon = atoi(bPtr + 1);
			
			if (ePtr != NULL) {
				addend = atoi(ePtr + 1);

				if (positive == 0)
					addend = - addend;
			}
			
			else
				addend = 0;

			numStr[0] = '\0';
		}
		
		else
		{
			addend = atoi(numStr);

			if (addend == 0)
				break;
		}

		printf("\n");

		time0 = clock();

		result = ECMMethod(numStr, base, expon, addend);

		if (result == 0)
			printf("can't completely factor this number\n");
		
		else if (result == 1)
		{
			printf("%s\nnumber is composite factors:\n", cfac[0]);
			
			for (i = 1; i < cnt; i++)
				if (strcmp(cexp[i], "1") == 0)
					printf("\t%s\n", cfac[i]);
				else
					printf("\t%s ^ %s\n", cfac[i], cexp[i]);
		}
		
		else if (result == 2)
			printf("%s\nnumber is prime:\n", cfac[0]);

		else if (result == 3)
			printf("number or prime factor is too large\n");

		time = (clock() - time0) / (double) CLK_TCK;
		printf("total time required: %f seconds\n", time);
		printf("\n");
	}

	return 0;
}

Solution of the 8-Puzzle Using Java by James Pate Williams, Jr.

/*
	Author:	James Pate Williams, Jr.

	Solution of 8-puzzle using A* search
*/

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class Puzzle8Panel extends JPanel {
	char[] s;
	int deltaX, deltaY;
	int x0, x1, y0, y1;
	
	public Puzzle8Panel(int iWidth, int iHeight, char[] solution) {
		x0 = iWidth / 8;
		x1 = 7 * x0;
		y0 = iHeight / 8;
		y1 = 7 * y0;
		deltaX = (x1 - x0) / 3;
		deltaY = (y1 - y0) / 3;
		s = new char[9];
		s = solution;
	}
	
	public void sevenSegmentDisplay(Graphics g, char digit,
		int x, int y, int xUnit, int yUnit) {
		int xInc = xUnit / 10;
		int yInc = yUnit / 10;
		int xPoint1 = x + xInc;
		int yPoint1 = y + yInc;
		int xPoint2 = x + xUnit - xInc;
		int yPoint2 = yPoint1;
		int xPoint3 = xPoint1;
		int yPoint3 = y + yUnit / 2;
		int xPoint4 = xPoint2;
		int yPoint4 = yPoint3;
		int xPoint5 = xPoint3;
		int yPoint5 = y + yUnit - yInc;
		int xPoint6 = xPoint4;
		int yPoint6 = yPoint5;

		g.setColor(Color.white);
		switch (digit) {
			case '0':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint6, yPoint6);
				g.drawLine(xPoint6, yPoint6, xPoint5, yPoint5);
				g.drawLine(xPoint5, yPoint5, xPoint1, yPoint1);
				break;
			case '1':
				g.drawLine(xPoint1, yPoint1, xPoint5, yPoint5);
				break;
			case '2':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint4, yPoint4);
				g.drawLine(xPoint4, yPoint4, xPoint3, yPoint3);
				g.drawLine(xPoint3, yPoint3, xPoint5, yPoint5);
				g.drawLine(xPoint5, yPoint5, xPoint6, yPoint6);
				break;
			case '3':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint4, yPoint4);
				g.drawLine(xPoint4, yPoint4, xPoint3, yPoint3);
				g.drawLine(xPoint4, yPoint4, xPoint6, yPoint6);
				g.drawLine(xPoint6, yPoint6, xPoint5, yPoint5);
				break;
			case '4':
				g.drawLine(xPoint1, yPoint1, xPoint3, yPoint3);
				g.drawLine(xPoint3, yPoint3, xPoint4, yPoint4);
				g.drawLine(xPoint4, yPoint4, xPoint2, yPoint2);
				g.drawLine(xPoint4, yPoint4, xPoint6, yPoint6);
				break;
			case '5':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint1, yPoint1, xPoint3, yPoint3);
				g.drawLine(xPoint3, yPoint3, xPoint4, yPoint4);
				g.drawLine(xPoint4, yPoint4, xPoint6, yPoint6);
				g.drawLine(xPoint6, yPoint6, xPoint5, yPoint5);
				break;
			case '6':
				g.drawLine(xPoint1, yPoint1, xPoint3, yPoint3);
				g.drawLine(xPoint3, yPoint3, xPoint4, yPoint4);
				g.drawLine(xPoint4, yPoint4, xPoint6, yPoint6);
				g.drawLine(xPoint6, yPoint6, xPoint5, yPoint5);
				g.drawLine(xPoint5, yPoint5, xPoint3, yPoint3);
				break;
			case '7':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint6, yPoint6);
				break;
			case '8':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint6, yPoint6);
				g.drawLine(xPoint6, yPoint6, xPoint5, yPoint5);
				g.drawLine(xPoint5, yPoint5, xPoint1, yPoint1);
				g.drawLine(xPoint3, yPoint3, xPoint4, yPoint4);
				break;
			case '9':
				g.drawLine(xPoint1, yPoint1, xPoint2, yPoint2);
				g.drawLine(xPoint2, yPoint2, xPoint6, yPoint6);
				g.drawLine(xPoint1, yPoint1, xPoint3, yPoint3);
				g.drawLine(xPoint3, yPoint3, xPoint4, yPoint4);
				break;
		}
	}		
				  
	public void paintComponent(Graphics g) {
		int i, j, x, y;
  		int xUnit = deltaY / 9;
  		int yUnit = deltaY / 15;
		
		super.paintComponent(g);
		y = y0;
		for (i = 0; i < 3; i++) {
			x = x0;
			for (j = 0; j < 3; j++) {
				g.setColor(Color.white);
				g.drawRect(x, y, deltaX, deltaY);
				g.setColor(Color.black);
				g.fillRect(x, y, deltaX, deltaY);
				sevenSegmentDisplay(g, s[3 * i + j], x, y, deltaX, deltaY);
				x += deltaX;
			}
			y += deltaY;
		}		
	}

	public void setSolution(char[] solution) {
		s = new char[9];
		s = solution;
	}
}

class Puzzle8Frame extends JFrame implements Runnable {
	boolean next;
	int iHeight, iWidth;
	JButton jButton1 = new JButton();
	JPanel jPanel = new JPanel();
	BorderLayout borderLayout = new BorderLayout();
	Puzzle8Panel puzzle8Panel;
	
	// step 3 - percentage size the window
	void setDesktopSize(JFrame frame, int wPerc, int hPerc) {
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		iWidth = screen.width * wPerc / 100;
		iHeight = screen.height * hPerc / 100;
		frame.setSize(iWidth, iHeight);
	}
	
	// step 4 - center the window
	void centerOnScreen(JFrame frame) {
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension window = frame.getSize();
		int iCenterX = screen.width / 2;
		int iCenterY = screen.height / 2;
		frame.setLocation(iCenterX - window.width / 2, iCenterY - window.height / 2);
	}
	
	public Puzzle8Frame(char[] solution) {
		String title = "Puzzle8 by James Pate Williams, Jr. (c) 2001";
		next = false;
		jButton1.setToolTipText("Perform one iteration of algorithm");
		jButton1.setText("Next");
		jButton1.setVerticalAlignment(SwingConstants.BOTTOM);
		jButton1.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jButton1_actionPerformed(e);
			}
    		});
    		this.getContentPane().setLayout(borderLayout);
		setTitle(title);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				System.exit(0);
			}
		});
		setDesktopSize(this, 100, 100);
		centerOnScreen(this);
		Container contentPane = getContentPane();
		contentPane.add(jPanel, BorderLayout.SOUTH);
		jPanel.add(jButton1, BorderLayout.CENTER);
		puzzle8Panel = new Puzzle8Panel(iWidth, iHeight, solution);
		contentPane.add(puzzle8Panel, BorderLayout.CENTER);
		this.show();
		(new Thread(this)).run();
	}

	public boolean getNext() {
		return next;
	}

	public void setNext(boolean n) {
		next = n;
	}

	void jButton1_actionPerformed(ActionEvent e) {
		next = true;
	}
	
	public void run() {
		Thread.yield();
	}

	public void draw(char[] solution) {
		puzzle8Panel.setSolution(solution);
		puzzle8Panel.paintComponent(getGraphics());
	}
}

class Puzzle {
	int g, nodesExpanded;
	int[][] board;
	Date date;
	Random random;
	public static final int MaxMoves = 100;

	public Puzzle() {
		boolean found;
		int digit, i, j, k;
		int[] placed = new int[9];
		
		date = new Date();
		random = new Random(date.getTime());
		for (i = 0; i < 9; i++)
			placed[i] = 0;
		board = new int[3][3];
		g = nodesExpanded = 0;
		for (i = 0; i < 3; i++)
			for (j = 0; j < 3; j++)
				board[i][j] = 0;
		for (i = 0; i < 9; i++) {
			found = false;
			do {
				digit = random.nextInt(9);
				found = placed[digit] == 0;
				if (found)
					placed[digit] = 1;
			} while (!found);
			do {
				j = random.nextInt(3);
				k = random.nextInt(3);
				found = board[j][k] == 0;
				if (found)
					board[j][k] = digit;
			} while (!found);
		}
	}

	int getNodesExpanded() {
		return nodesExpanded;
	}

	int expand(int[][] square, int[][][] tempSquare) {
		int b = - 1, col = - 1, i, j, k, row = - 1;

		for (i = 0; i < 4; i++)
			for (j = 0; j < 3; j++)
				for (k = 0; k < 3; k++)
					tempSquare[i][j][k] = square[j][k];
		for (i = 0; i < 3; i++) {
			for (j = 0; j < 3; j++) {
				if (square[i][j] == 0) {
					row = i;
					col = j;
					break;
				}
			}
		}
		if (row == 0 && col == 0) {
			tempSquare[0][0][0] = tempSquare[0][0][1];
			tempSquare[0][0][1] = 0;
			tempSquare[1][0][0] = tempSquare[1][1][0];
			tempSquare[1][1][0] = 0;
			b = 2;
		}
		else if (row == 0 && col == 1) {
			tempSquare[0][0][1] = tempSquare[0][0][0];
			tempSquare[0][0][0] = 0;
			tempSquare[1][0][1] = tempSquare[1][1][1];
			tempSquare[1][1][1] = 0;
			tempSquare[2][0][1] = tempSquare[2][0][2];
			tempSquare[2][0][2] = 0;
			b = 3;
		}
		else if (row == 0 && col == 2) {
			tempSquare[0][0][2] = tempSquare[0][0][1];
			tempSquare[0][0][1] = 0;
			tempSquare[1][0][2] = tempSquare[1][1][2];
			tempSquare[1][1][2] = 0;
			b = 2;
		}
		else if (row == 1 && col == 0) {
			tempSquare[0][1][0] = tempSquare[0][0][0];
			tempSquare[0][0][0] = 0;
			tempSquare[1][1][0] = tempSquare[1][1][1];
			tempSquare[1][1][1] = 0;
			tempSquare[2][1][0] = tempSquare[2][2][0];
			tempSquare[2][2][0] = 0;
			b = 3;
		}
		else if (row == 1 && col == 1) {
			tempSquare[0][1][1] = tempSquare[0][1][0];
			tempSquare[0][1][0] = 0;
			tempSquare[1][1][1] = tempSquare[1][0][1];
			tempSquare[1][0][1] = 0;
			tempSquare[2][1][1] = tempSquare[2][1][2];
			tempSquare[2][1][2] = 0;
			tempSquare[3][1][1] = tempSquare[3][2][1];
			tempSquare[3][2][1] = 0;
			b = 4;
		}
		else if (row == 1 && col == 2) {
			tempSquare[0][1][2] = tempSquare[0][0][2];
			tempSquare[0][0][2] = 0;
			tempSquare[1][1][2] = tempSquare[1][1][1];
			tempSquare[1][1][1] = 0;
			tempSquare[2][1][2] = tempSquare[2][2][2];
			tempSquare[2][2][2] = 0;
			b = 3;
		}
		else if (row == 2 && col == 0) {
			tempSquare[0][2][0] = tempSquare[0][1][0];
			tempSquare[0][1][0] = 0;
			tempSquare[1][2][0] = tempSquare[1][2][1];
			tempSquare[1][2][1] = 0;
			b = 2;
		}
		else if (row == 2 && col == 1) {
			tempSquare[0][2][1] = tempSquare[0][2][0];
			tempSquare[0][2][0] = 0;
			tempSquare[1][2][1] = tempSquare[1][1][1];
			tempSquare[1][1][1] = 0;
			tempSquare[2][2][1] = tempSquare[2][2][2];
			tempSquare[2][2][2] = 0;
			b = 3;
		}
		else if (row == 2 && col == 2) {
			tempSquare[0][2][2] = tempSquare[0][2][1];
			tempSquare[0][2][1] = 0;
			tempSquare[1][2][2] = tempSquare[1][1][2];
			tempSquare[1][1][2] = 0;
			b = 2;
		}
		return b;
	}

	int heuristic(int[][] square) {
		return ManhattenDistance(square);
	}

	boolean move() {
		int b, count, i, j, k, min;
		int[] f = new int[4], index = new int[4];
		int[][][] tempSquare = new int[4][3][3];

		if (board[0][0] == 1 && board[0][1] == 2 && board[0][2] == 3 &&
			board[1][0] == 8 && board[1][1] == 0 && board[1][2] == 4 &&
			board[2][0] == 7 && board[2][1] == 6 && board[2][2] == 5)
			return true;
		b = expand(board, tempSquare);
		for (i = 0; i < b; i++) {
			f[i] = g + heuristic(tempSquare[i]);
			for (j = 0; j < 3; j++)
				for (k = 0; k < 3; k++)
					board[j][k] = tempSquare[i][j][k];
		}
		// find the node of minimum f
		min = f[0];
		for (i = 1; i < b; i++)
			if (f[i] < min)
				min = f[i];
		for (count = i = 0; i < b; i++)
			if (f[i] == min)
				index[count++] = i;
		i = index[random.nextInt(count)];
		// increment the cost of the path thus far
		g++;
		nodesExpanded += b;
		for (j = 0; j < 3; j++)
			for (k = 0; k < 3; k++)
				board[j][k] = tempSquare[i][j][k];
		return false;
	}

	int outOfPlace(int[][] square) {
		int i, j, oop = 0;
		int[][] goal = new int[3][3];
		
		goal[0][0] = 1;
		goal[0][1] = 2;
		goal[0][2] = 3;
		goal[1][0] = 8;
		goal[1][1] = 0;
		goal[1][2] = 4;
		goal[2][0] = 7;
		goal[2][1] = 6;
		goal[2][2] = 5;
		for (i = 0; i < 3; i++)
			for (j = 0; j < 3; j++)
				if (square[i][j] != goal[i][j])
					oop++;
		return oop;
	}

	int ManhattenDistance(int[][] square) {
		// city block or Manhatten distance heuristic
		int md = 0;

		if (square[0][0] == 1)
			md += 0;
		else if (square[0][0] == 2)
			md += 1;
		else if (square[0][0] == 3)
			md += 2;
		else if (square[0][0] == 4)
			md += 3;
		else if (square[0][0] == 5)
			md += 4;
		else if (square[0][0] == 6)
			md += 3;
		else if (square[0][0] == 7)
			md += 2;
		else if (square[0][0] == 8)
			md += 1;
		if (square[0][1] == 1)
			md += 1;
		else if (square[0][1] == 2)
			md += 0;
		else if (square[0][1] == 3)
			md += 1;
		else if (square[0][1] == 4)
			md += 2;
		else if (square[0][1] == 5)
			md += 3;
		else if (square[0][1] == 6)
			md += 2;
		else if (square[0][1] == 7)
			md += 3;
		else if (square[0][1] == 8)
			md += 2;
		if (square[0][2] == 1)
			md += 2;
		else if (square[0][2] == 2)
			md += 1;
		else if (square[0][2] == 3)
			md += 0;
		else if (square[0][2] == 4)
			md += 1;
		else if (square[0][2] == 5)
			md += 2;
		else if (square[0][2] == 6)
			md += 3;
		else if (square[0][2] == 7)
			md += 4;
		else if (square[0][2] == 8)
			md += 3;
		if (square[1][0] == 1)
			md += 1;
		else if (square[1][0] == 2)
			md += 2;
		else if (square[1][0] == 3)
			md += 3;
		else if (square[1][0] == 4)
			md += 2;
		else if (square[1][0] == 5)
			md += 3;
		else if (square[1][0] == 6)
			md += 2;
		else if (square[1][0] == 7)
			md += 1;
		else if (square[1][0] == 8)
			md += 0;
		if (square[1][1] == 1)
			md += 2;
		else if (square[1][1] == 2)
			md += 1;
		else if (square[1][1] == 3)
			md += 2;
		else if (square[1][1] == 4)
			md += 1;
		else if (square[1][1] == 5)
			md += 2;
		else if (square[1][1] == 6)
			md += 1;
		else if (square[1][1] == 7)
			md += 2;
		else if (square[1][1] == 8)
			md += 1;
		if (square[1][2] == 1)
			md += 3;
		else if (square[1][2] == 2)
			md += 2;
		else if (square[1][2] == 3)
			md += 1;
		else if (square[1][2] == 4)
			md += 0;
		else if (square[1][2] == 5)
			md += 1;
		else if (square[1][2] == 6)
			md += 2;
		else if (square[1][2] == 7)
			md += 3;
		else if (square[1][2] == 8)
			md += 2;
		if (square[2][0] == 1)
			md += 2;
		else if (square[2][0] == 2)
			md += 3;
		else if (square[2][0] == 3)
			md += 4;
		else if (square[2][0] == 4)
			md += 3;
		else if (square[2][0] == 5)
			md += 2;
		else if (square[2][0] == 6)
			md += 1;
		else if (square[2][0] == 7)
			md += 0;
		else if (square[2][0] == 8)
			md += 1;
		if (square[2][1] == 1)
			md += 3;
		else if (square[2][1] == 2)
			md += 2;
		else if (square[2][1] == 3)
			md += 3;
		else if (square[2][1] == 4)
			md += 2;
		else if (square[2][1] == 5)
			md += 1;
		else if (square[2][1] == 6)
			md += 0;
		else if (square[2][1] == 7)
			md += 1;
		else if (square[2][1] == 8)
			md += 2;
		if (square[2][2] == 1)
			md += 4;
		else if (square[2][2] == 2)
			md += 3;
		else if (square[2][2] == 3)
			md += 2;
		else if (square[2][2] == 4)
			md += 1;
		else if (square[2][2] == 5)
			md += 0;
		else if (square[2][2] == 6)
			md += 1;
		else if (square[2][2] == 7)
			md += 2;
		else if (square[2][2] == 8)
			md += 3;
		return md;
	}

	int solve(char[][] solution) {
		boolean found;
		int i, j, k, m = 0;

		do {
			for (i = k = 0; i < 3; i++)
				for (j = 0; j < 3; j++)
					solution[m][k++] = (char) (board[i][j] + '0');
			found = move();
			m++;
		} while (!found && m < MaxMoves);
		for (i = k = 0; i < 3; i++)
			for (j = 0; j < 3; j++)
				solution[m][k++] = (char) (board[i][j] + '0');
		return m;
	}
}

class Puzzle8 implements Runnable {
	char[][] solution = null;
	int moves;
	
	public Puzzle8 () {
		solution = new char[Puzzle.MaxMoves + 1][9];
		do {
			Puzzle puzzle = new Puzzle();
			moves = puzzle.solve(solution);
		} while (moves == Puzzle.MaxMoves);
	}

	public void run() {
		Puzzle8Frame puzzle8Frame = new Puzzle8Frame(solution[0]);
		
		System.out.println("moves = " + moves);
		for (int i = 0; i < moves; i++) {
			while (!puzzle8Frame.getNext())
				Thread.yield();
			puzzle8Frame.setNext(false);
			puzzle8Frame.draw(solution[i]);
		}
		puzzle8Frame.draw(solution[moves]);
	}

	static void main(String[] arg) {
		(new Puzzle8()).run();
	}
}				
	

Plant Growth L-System in Java by James Pate Williams, Jr.

/*
	Author: James Pate Williams, Jr.

	Stochastic L-System to draw a plant. See "Simulating Plant Growth" by
	Marco Grubert, Crossroads, the ACM Student Magazine Issue 8.2, Winter
	2001, pages 20-27.
*/

import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.util.*;
import javax.swing.*;

class Cursor {
	private double factor, rTheta;
	private int height, theta, width, x, x0, y, y0;

	public Cursor() {
	}

	public Cursor(int w, int h) {
		width = w;
		height = h;
		factor = Math.PI / 180.0;
		theta = 270;
		rTheta = factor * theta;
		x0 = width / 2;
		y0 = height;
		x = 0;
		y = 0;
	}

	public Cursor(int iw, int ih, int iTheta, int ix, int iy) {
		width = iw;
		height = ih;
		theta = iTheta;
		factor = Math.PI / 180.0;
		rTheta = factor * theta;
		x0 = width / 2;
		y0 = height;
		x = ix;
		y = iy;
	}

	public void F(Graphics g, int n) {
		double nX = n * Math.cos(rTheta) + x, nY = n * Math.sin(rTheta) + y;
		int X = x, Y = y;

		x = (int) nX;
		y = (int) nY;
		g.drawLine(X + x0, Y + y0, x + x0, y + y0);
	}

	public void f(Graphics g, int n) {
		double nX = n * Math.cos(rTheta) + x, nY = n * Math.sin(rTheta) + y;

		x = (int) nX;
		y = (int) nY;
		g.translate(x + x0, y + y0);
	}

	public void plus(int alpha) {
		theta = (theta - alpha) % 360;
		if (theta < 0)
			theta += 360;
		rTheta = factor * theta;
	}
	
	public void minus(int alpha) {
		theta = (theta + alpha) % 360;
		if (theta < 0)
			theta += 360;
		rTheta = factor * theta;
	}

	public void exclamation() {
		theta = (theta + 180) % 360;
		if (theta < 0)
			theta += 360;
		rTheta = factor * theta;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public int getTheta() {
		return theta;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	public int getX0() {
		return x0;
	}

	public int getY0() {
		return y0;
	}
}

class PlantPanel extends JPanel {
	int depth;
	Cursor cursor = null;
	Random random = null;

	public PlantPanel(int iDepth, int iWidth, int iHeight, int seed) {
		depth = iDepth;
		cursor = new Cursor(iWidth, iHeight);
		random = new Random(seed);
	}
	
	public void lSystem1(Graphics g, int d, int depth, int n, int width, int height, 
			    int theta, int x, int y) {
		int alpha = 20;
		Cursor cursor = new Cursor(width, height, theta, x, y);
		Cursor stackCursor = null;

		if (d == depth)
			return;
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(),
			cursor.getTheta(), cursor.getX(), cursor.getY());
		stackCursor.plus(alpha);
		stackCursor.F(g, n);
		theta = stackCursor.getTheta();
		x = stackCursor.getX();
		y = stackCursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(),
			cursor.getTheta(), cursor.getX(), cursor.getY());
		stackCursor.minus(alpha);
		stackCursor.F(g, n);
		theta = stackCursor.getTheta();
		x = stackCursor.getX();
		y = stackCursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
	}

	public void lSystem2(Graphics g, int d, int depth, int n, int width, int height, 
			    int theta, int x, int y) {
		int alpha = 20;
		Cursor cursor = new Cursor(width, height, theta, x, y);
		Cursor stackCursor = null;

		if (d == depth)
			return;
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(),
			cursor.getTheta(), cursor.getX(), cursor.getY());
		stackCursor.plus(alpha);
		stackCursor.F(g, n);
		theta = stackCursor.getTheta();
		x = stackCursor.getX();
		y = stackCursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
	}

	public void lSystem3(Graphics g, int d, int depth, int n, int width, int height, 
			    int theta, int x, int y) {
		int alpha = 20;
		Cursor cursor = new Cursor(width, height, theta, x, y);
		Cursor stackCursor = null;

		if (d == depth)
			return;
		cursor.F(g, n);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
		stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(),
			cursor.getTheta(), cursor.getX(), cursor.getY());
		stackCursor.minus(alpha);
		stackCursor.F(g, n);
		theta = stackCursor.getTheta();
		x = stackCursor.getX();
		y = stackCursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
	}

	public void lSystem0(Graphics g, int d, int depth, int n, int width, int height, 
			    int theta, int x, int y) {
		double r = random.nextDouble();

		if (d == depth)
			return;
		if (r <= 0.33) 
			lSystem1(g, d, depth, n, width, height, theta, x, y);
		else if (r <= 0.66)
			lSystem2(g, d, depth, n, width, height, theta, x, y);
		else
			lSystem3(g, d, depth, n, width, height, theta, x, y);
		theta = cursor.getTheta();
		x = cursor.getX();
		y = cursor.getY();
		lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y);
	}

	public void lSystem(Graphics g, int d, int depth, int n, int width, int height, 
			    int theta, int x, int y) {
		lSystem0(g, d, depth, n, width, height, theta, x, y);
	}

	public void paintComponent(Graphics g) {
		int n = 120;
		int width = cursor.getWidth(), height = cursor.getHeight();
		int theta = cursor.getTheta(), x0 = cursor.getX0(), y0 = cursor.getY0();
		
		lSystem(g, 0, depth, n, width, height, theta, 0, 0);
	}
}

class PlantFrame extends JFrame {
	int iHeight, iWidth;
	PlantPanel plantPanel;
	
	// step 3 - percentage size the window
	void setDesktopSize(JFrame frame, int wPerc, int hPerc) {
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		iWidth = screen.width * wPerc / 100;
		iHeight = screen.height * hPerc / 100;
		frame.setSize(iWidth, iHeight);
	}
	
	// step 4 - center the window
	void centerOnScreen(JFrame frame) {
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension window = frame.getSize();
		int iCenterX = screen.width / 2;
		int iCenterY = screen.height / 2;
		frame.setLocation(iCenterX - window.width / 2, iCenterY - window.height / 2);
	}
	
	public PlantFrame(int depth, int seed) {
		String title = "Plant by James Pate Williams, Jr. (c) 2001";

		setTitle(title);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				System.exit(0);
			}
		});
		setDesktopSize(this, 100, 100);
		centerOnScreen(this);
		Container contentPane = getContentPane();
		plantPanel = new PlantPanel(depth, iWidth, iHeight, seed);
		contentPane.add(plantPanel, BorderLayout.CENTER);
		this.show();
	}
}

class Plant {
	public static void main(String[] args) {
		if (args.length != 2) {
			System.out.println("usage: java Plant depth seed");
			System.out.println("where 5 <= depth <= 8 and seed >= 1");
			System.exit(0);
		}
		int depth = (new Integer(args[0])). intValue();
		if (depth < 5 || depth > 8) {
			System.out.println("depth not in range 5 <= depth <= 8!");
			System.exit(0);
		}
		int seed = (new Integer(args[1])).intValue();
		if (seed < 1) {
			System.out.println("seed must be >= 1");
			System.exit(0);
		}
		PlantFrame plantFrame = new PlantFrame(depth, seed);
	}
}

Wallace and Freuder’s Min-Conflicts Hill Climber Solution of the N-Queens Problem

/*
	Author:	James Pate Williams, Jr. (c) 2000

	Min-conflicts hill-climbing applied to N-Queens problem.
	Wallace and Freuder's algorithm with an unbiased
	preprocessor.
*/

#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;

const bool Debug = true;
const int MaxRepairs = 1000000;

int conflicts(int a, int i, int n, vector<int> &Q) {
	int b, c = 0, j;

	for (j = 0; j < n; j++) {
		b = Q[j];
		if (i != j && a != - 1 && b != - 1) {
			if (a == b) c++;
			if (i - j == a - b || i - j == b - a) c++;
		}
	}
	return c;
}

int constraintsViolated(vector<int> &Q) {
	int a, b, c = 0, i, j, n;
	
	n = Q.size();
	for (i = 0; i < n; i++) {
		a = Q[i];
		for (j = 0; j < n; j++) {
			b = Q[j];
			if (i != j && a != - 1 && b != - 1) {
				if (a == b) c++;
				if (i - j == a - b || i - j == b - a) c++;
			}
		}
	}
	return c;
}

int mchcAlgorithm(int n, vector<int> &compoundLabel) {
	bool commit, firstLoop = true;
	double p = 0.1, r;
	int c, i, index, j, minConflict, v;
	int repairs = 0;
	vector<int> conflict, domain, position;

	// preprocessing
	for (i = 0; i < n; i++) {
		conflict.erase(conflict.begin(), conflict.end());
		for (j = 0; j < n; j++)
			domain.push_back(j);
		for (commit = false, j = 0; !commit && j < n; j++) {
			v = domain[rand() % domain.size()];
			vector<int>::iterator vIterator = find(domain.begin(), domain.end(), v);
			domain.erase(vIterator);
			compoundLabel[i] = v;
			c = conflicts(v, i, i, compoundLabel);
			conflict.push_back(c);
			if (c == 0) commit = true;
		}
		if (!commit) {
			minConflict = conflict[0];
			for (j = 1; j < n; j++)
				if (conflict[j] < minConflict) minConflict = conflict[j];
			position.erase(position.begin(), position.end());
			for (j = 0; j < n; j++)
				if (minConflict == conflict[j]) position.push_back(j);
			compoundLabel[i] = position[rand() % position.size()];	
		}
	}
	for (;;) {
		conflict.erase(conflict.begin(), conflict.end());
		for (i = 0, j = 0; i < n; i++) {
			c = conflicts(compoundLabel[i], i, n, compoundLabel);
			conflict.push_back(c);
			j += c;
		}
		if (firstLoop) {
			cout << "conflicts after preprocessor: " << j << endl;
			firstLoop = false;
		}
		if (j == 0) break;
		position.erase(position.begin(), position.end());
		for (i = 0; i < n; i++)
			if (conflict[i] >= 1) position.push_back(i);
		index = position[rand() % position.size()];
		r = (double) rand() / RAND_MAX;
		if (r <= p)
			compoundLabel[index] = rand() % n;
		else {
			for (i = 0; i < n; i++) {
				compoundLabel[index] = i;
				conflict[i] = conflicts(i, index, n, compoundLabel);
				repairs++;
				if (repairs == MaxRepairs) return repairs;
			}
			minConflict = conflict[0];
			for (i = 1; i < n; i++)
				if (conflict[i] < minConflict) minConflict = conflict[i];
			position.erase(position.begin(), position.end());
			for (i = 0; i < n; i++)
				if (minConflict == conflict[i]) position.push_back(i);
			compoundLabel[index] = position[rand() % position.size()];
		}
	}
	return repairs;
}

void printSolution(vector<int> &solution) {
	char hyphen[256];
	int column, i, i4, n = solution.size(), row;

	if (n <= 10) {
		for (i = 0; i < n; i++) {
			i4 = i * 4;
			hyphen[i4 + 0] = '-';
			hyphen[i4 + 1] = '-';
			hyphen[i4 + 2] = '-';
			hyphen[i4 + 3] = '-';
		}
		i4 = i * 4;
		hyphen[i4 + 0] = '-';
		hyphen[i4 + 1] = '\n';
		hyphen[i4 + 2] = '\0';
		for (row = 0; row < n; row++) {
			column = solution[row];
			cout << hyphen;
			for (i = 0; i < column; i++)
				cout << "|   ";
			cout << "| Q ";
			for (i = column + 1; i < n; i++)
				cout << "|   ";
			cout << '|' << endl;
		}
		cout << hyphen;
	}
	else
		for (row = 0; row < n; row++)
			cout << row << ' ' << solution[row] << endl;
}

int main(int argc, char *argv[]) {
	if (argc != 2) {
		cout << "usage: " << argv[0] << " numberOfQueens" << endl;
		exit(1);
	}
	int n = atoi(argv[1]), repairs;
	double seconds;
	clock_t time0, time1;
	vector<int> solution(n, - 1);
	srand(time(NULL));
	time0 = clock();
	repairs = mchcAlgorithm(n, solution);
	time1 = clock();
	time1 -= time0;
	seconds = (double) time1 / CLOCKS_PER_SEC;
	if (Debug) printSolution(solution);
	cout << "Repairs: " << repairs << endl;
	cout << "seconds: " << seconds << endl;
	return 0;
}			
		

Brute Force Solution of the N-Queens Problem by James Pate Williams, Jr.

/*
*  NQueensBruteForce.cpp
*  NQueensBruteForce
*
*	Brute force determination of the total number of
*	solutions of the n-queens constraint satisfaction
*	problem (CSP). Order n! complexity algorithm.
*
*  Created by James Pate Williams, Jr. on 12/10/07.
*  Copyright 2007. All rights reserved.
*
*/

#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

int ConstraintViolations(std::vector<int> &Q, int &cvCount) {
	int a, b, cv = 0, i, j, n;

	n = Q.size();

	for (i = 0; i < n; i++) {

		a = Q[i];

		for (j = 0; j < n; j++) {
			b = Q[j];

			if (i != j && a != -1 && b != -1) {

				if (a == b)
					cv++;

				if (i - j == a - b || i - j == b - a)
					cv++;
			}
		}
	}

	cvCount++;
	return cv;
}

void PrintSolution(std::vector<int> &solution) {
	char hyphen[256];
	int column, i, i4, n = solution.size(), row;

	if (n <= 10) {
		for (i = 0; i < n; i++) {
			i4 = i * 4;
			hyphen[i4 + 0] = '-';
			hyphen[i4 + 1] = '-';
			hyphen[i4 + 2] = '-';
			hyphen[i4 + 3] = '-';
		}
		i4 = i * 4;
		hyphen[i4 + 0] = '-';
		hyphen[i4 + 1] = '\n';
		hyphen[i4 + 2] = '\0';
		for (row = 0; row < n; row++) {
			column = solution[row];
			std::cout << hyphen;
			for (i = 0; i < column; i++)
				std::cout << "|   ";
			std::cout << "| Q ";
			for (i = column + 1; i < n; i++)
				std::cout << "|   ";
			std::cout << '|' << std::endl;
		}
		std::cout << hyphen;
	}
	else
		for (row = 0; row < n; row++)
			std::cout << row << ' ' << solution[row] << std::endl;
}

int main(int argc, char * const argv[])
{
	if (argc != 3) {
		std::cout << "usage: " << argv[0] << " numberOfQueens print";
		std::cout << std::endl;
		exit(-1);
	}

	int numberOfQueens = atoi(argv[1]);

	if (numberOfQueens <= 0) {
		std::cout << "numberOfQueens must be positive" << std::endl;
		exit(-1);
	}

	int count = 0, i, cvCount = 0, print = atoi(argv[2]), space = 0;
	clock_t clock0;
	std::vector<int> queenVector;

	clock0 = clock();
	for (i = 0; i < numberOfQueens; i++)
		queenVector.push_back(i);

	do {

		int cv = ConstraintViolations(queenVector, cvCount);

		if (cv == 0) {
			count++;

			if (print == 1) {
				PrintSolution(queenVector);
				std::cout << std::endl;
			}
		}
		space++;
	} while (std::next_permutation(
		queenVector.begin(),
		queenVector.end(),
		std::less<int>()));

	double seconds = (double)(clock() - clock0) / CLOCKS_PER_SEC;

	std::cout << "search space size     = " << space << std::endl;
	std::cout << "number of con checks  = " << cvCount << std::endl;
	std::cout << "number of solutions   = " << count << std::endl;
	std::cout << "total time (seconds)  = " << seconds << std::endl;
	return 0;
}
N-Queens Problem for Four Queens 4! = 24 Search Space

Latest Sorting C++ Code

#pragma once
// Insertion sort, heap sort, and quick sort algorithms
// From "Algortihms" by Thomas H. Cormen, et. al.
// Selection sort, Singleton's sort, and Tree Sort 3, etc.
// From "Sorting and Sort Systems" by Harold Lorin
class Sorting {
public:
	// Translated from Lorin's PL/I procedure
	static void BasicExchange(long long tosort[], int number);
	// Translated from Lorin's PL/I procedure
	static void StandardExchange(long long tosort[], int number);
	static void InsertionSort(long long a[], int n);
	static void SelectionSort(long long a[], int n);
	// CACM Algorithm 175
	static void SimpleShifting(long long tosort[], int number);
	// CACM Algorithm 201 1963
	static void ShellSort(long long tosort[], int number);
	static void HeapSort(long long a[], int n);
	static void QuickSort(long long a[], int n);
	// CACM Algorithm 347 Ricahrd C. Singleton 1968
	// Translated from Lorin's PL/I procedure
	static void SingletonsSort(long long a[], int n);
	// CACM Algorithm 245 Robert W. Floyd 1964
	// Translated from Lorin's PL/I procedure
	static void TreeSort3(long long a[], int n);
	// see "Algortihms" by Thomas H. Cormen, et. al.
	// A is the array to be sorted, B is the sorted
	// array and k is maximum number in A
	static void CountingSort(
		long long A[],
		long long B[],
		long long C[],
		int n, long long k);
private:
	// five helper methods for Heap Sort
	static int Parent(int i);
	static int Left(int i);
	static int Right(int i);
	static void BuildHeap(long long a[], int n, int& heapSize);
	static void Heapify(long long a[], int i, int n, int& heapSize);
	/* helper functions for SETHEAP
	static void SWOPHEAP(long long A[], int n, long long& in, long long& out);
	static void INHEAP(long long A[], int& n, long long& in);
	static void OUTHEAP(long long A[], int& n, long long& out);
	static void SETHEAP(long long A[], int n);*/
	// helper methods for Quick Sort
	static int Partition(long long a[], int n, int lo, int hi);
	static void DoQuickSort(long long a[], int n, int p, int r);
	// helper function for Singleton's sort
	static void DoSingletonsSort(long long a[], int ii, int jj);
	// helper function for TreeSort3
	static void SiftUp(long long a[], int i, int n);
};
#include "Sorting.h"
#include <math.h>

void Sorting::BasicExchange(long long tosort[], int number)
{
    int adjust = 2 * (number / 2);
    int elimit, olimit;

    if (adjust < number)
    {
        elimit = adjust;
        olimit = adjust - 1;
    }
    else
    {
        elimit = number - 2;
        olimit = number - 1;
    }
odd:
    int passw = 1;
    int limit = olimit;
    int oddeve = 1;
pass:
    int excount = 0;

    for (int i = oddeve; i <= limit; i += 2)
    {
        if (tosort[i] > tosort[i + 1])
        {
            long long temp = tosort[i];

            tosort[i] = tosort[i + 1];
            tosort[i + 1] = temp;
            excount = 1;
        }
    }
    if (excount == 0)
        return;

    if (passw == 1)
    {
        passw = 0;
        oddeve = 0;
        limit = elimit;
        goto pass;
    }

    goto odd;
}

void Sorting::StandardExchange(long long tosort[], int number)
{
pass:
    int excount = 0;

    for (int i = 0; i < number - 1; i++)
    {
        if (tosort[i] > tosort[i + 1])
        {
            long long temp = tosort[i];

            tosort[i] = tosort[i + 1];
            tosort[i + 1] = temp;
            excount = 1;
        }
    }
    if (excount == 0)
        return;
    goto pass;
}

void Sorting::InsertionSort(long long a[], int n)
{
    for (int j = 1; j < n; j++)
    {
        long long key = a[j];
        int i = j - 1;

        while (i >= 0 && a[i] > key)
        {
            a[i + 1] = a[i];
            i--;
        }

        a[i + 1] = key;
    }
}

void Sorting::SelectionSort(long long a[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            if (a[i] > a[j])
            {
                long long t = a[i];

                a[i] = a[j];
                a[j] = t;
            }
        }
    }
}

void Sorting::SimpleShifting(long long tosort[], int number)
{
    for (int i = 0; i < number - 1; i++)
    {
        for (int j = i; j >= 0; j--)
        {
            if (tosort[j] > tosort[j + 1])
            {
                long long temp = tosort[j];

                tosort[j] = tosort[j + 1];
                tosort[j + 1] = temp;
            }
        }
    }
}

void Sorting::ShellSort(long long tosort[], int number)
{
    int lognumber = log2(number);
    int distance = (int)pow(2, lognumber) - 1;

    while (distance > 0)
    {
        int limit = number - distance;

        for (int j = 0; j < limit; j++)
        {
            for (int i = j; i >= 0; i--)
            {
                if (tosort[i + distance] < tosort[i])
                {
                    long long temp = tosort[i];

                    tosort[i] = tosort[i + distance];
                    tosort[i + distance] = temp;
                }
            }
        }

        distance /= 2;
    }
}

int Sorting::Parent(int i)
{
    return i / 2;
}

int Sorting::Left(int i)
{
    return 2 * i;
}

int Sorting::Right(int i) 
{
    return 2 * i + 1;
}

void Sorting::Heapify(long long a[], int i, int n, int& heapSize)
{
    int l = Left(i);
    int r = Right(i);
    int largest = -1;

    if (l < heapSize && a[l] > a[i])
        largest = l;
    else
        largest = i;

    if (r < heapSize && a[r] > a[largest])
        largest = r;

    if (largest != i)
    {
        long long t = a[i];

        a[i] = a[largest];
        a[largest] = t;

        Heapify(a, largest, n, heapSize);
    }
}

void Sorting::BuildHeap(long long a[], int n, int& heapSize)
{
    for (int i = n / 2; i >= 0; i--)
        Heapify(a, i, n, heapSize);
}

void Sorting::HeapSort(long long a[], int n)
{
    int heapSize = n;

    BuildHeap(a, n, heapSize);

    for (int i = n - 1; i >= 0; i--)
    {
        long long t = a[0];

        a[0] = a[i];
        a[i] = t;

        heapSize--;

        Heapify(a, 0, n, heapSize);
    }
}

void SWOPHEAP(long long A[], int n,
    long long& in, long long& out)
{
    if (in <= A[0])
        out = in;
    else
    {
        int i = 0;
        A[n] = in;
        out = A[0];
    scan:
        int j = i + i;
        if (j <= n - 1)
        {
            long long temp = A[j];
            long long temp1 = A[j + 1];
            if (temp1 < temp)
            {
                temp = temp1;
                j++;
            }
            if (temp < in)
            {
                A[i] = temp;
                i = j;
                goto scan;
            }
        }
        A[i] = in;
    }
}

void INHEAP(long long A[], int& n, long long& in)
{
    int i = n;
    n++;
scan:
    if (i > 0)
    {
        int j = i / 2;
        if (in < A[j])
        {
            A[i] = A[j];
            i = j;
            goto scan;
        }
    }
    A[i] = in;
}

void OUTHEAP(long long A[], int& n, long long& out)
{
    SWOPHEAP(A, n - 1, A[n - 1], out);
    n = n - 2;
}

void SETHEAP(long long A[], int n)
{
    int j = 0;
L:
    INHEAP(A, j, A[j + 1]);

    if (j < n - 2)
        goto L;
}

void HEAP(long long A[], int n)
{
    SETHEAP(A, n);

    for (int i = n - 1; i >= 1; i--)
        OUTHEAP(A, i, A[i]);
}

int Sorting::Partition(long long a[], int n, int lo, int hi)
{
    int pivotIndex = lo + (hi - lo) / 2;
    long long x = a[pivotIndex];
    long long t = x;

    a[pivotIndex] = a[hi];
    a[hi] = t;

    int storeIndex = lo;

    for (int i = lo; i < hi; i++)
    {
        if (a[i] < x)
        {
            t = a[i];
            a[i] = a[storeIndex];
            a[storeIndex++] = t;
        }
    }

    t = a[storeIndex];
    a[storeIndex] = a[hi];
    a[hi] = t;

    return storeIndex;
}

void Sorting::DoQuickSort(long long a[], int n, int p, int r)
{
    if (p < r)
    {
        int q = Partition(a, n, p, r);

        DoQuickSort(a, n, p, q - 1);
        DoQuickSort(a, n, q + 1, r);
    }
}

void Sorting::QuickSort(long long a[], int n)
{
    DoQuickSort(a, n, 0, n - 1);
}

void QuickerSort(long long tosort[], int number)
{
    const int limit = 20;
    int highlim = 0, lowlim, origin, partind, pivot;
    long long exch, temp = 0;
    int partablow[limit] = { 0 }, parttabhigh[limit] = { 0 };
    origin = partind = 0;
testsize:
    if (number - 1 - origin > 0)
    {
        pivot = (number - 1 + origin) / 2;
        temp = tosort[pivot];
        tosort[pivot] = tosort[origin];
        highlim = number - 1;

        for (lowlim = origin + 1; lowlim <= highlim; lowlim++)
        {
            if (tosort[lowlim] > temp)
            {
                for (highlim = highlim; highlim >= lowlim; highlim--)
                {
                    if (tosort[highlim] < temp)
                    {
                        exch = tosort[lowlim];
                        tosort[lowlim] = tosort[highlim];
                        tosort[highlim] = exch;
                        highlim = lowlim - 1;
                        goto limsmet;
                    }
                }
                highlim = lowlim - 1;
                goto limsmet;
            }
       }
    }
limsmet:
    tosort[origin] = tosort[highlim];
    tosort[highlim] = temp;
    if (2 * highlim > origin + number - 1)
    {
        partablow[partind] = origin;
        parttabhigh[partind] = highlim - 1;
        origin = highlim + 1;
    }
    else
    {
        partablow[partind] = highlim + 1;
        parttabhigh[partind] = number - 1;
        number = highlim - 1;
    }
    partind++;
    goto testsize;
    if (origin == number - 1)
        goto setpart;
    if (tosort[origin] > tosort[number - 1])
    {
        exch = tosort[origin];
        tosort[origin] = tosort[number - 1];
        tosort[number - 1] = exch;
    }
setpart:
    partind--;
    if (partind > -1)
    {
        origin = partablow[partind];
        number = parttabhigh[partind];
        goto testsize;
    }
}

void Sorting::DoSingletonsSort(long long a[], int ii, int jj)
{
    int m = 0;
    int i = ii;
    int j = jj;
    int iu[50] = { 0 };
    int il[50] = { 0 };
    int ij = 0, l = 1, k = 0;
    long long t = 0, tt = 0;
    Label1:
        if (i >= j)
            goto Label8;
        goto Label2;
    Label2:
        k = i;
        ij = (j + i) / 2;
        t = a[ij];
        if (a[i] <= t)
            goto Label3;
        a[ij] = a[i];
        a[i] = t;
        t = a[ij];
        goto Label3;
    Label3:
        l = j;
        if (a[j] >= t)
            goto Label5;
        a[ij] = a[j];
        a[j] = t;
        t = a[ij];
        if (a[i] <= t)
            goto Label5;
        a[ij] = a[i];
        a[i] = t;
        t = a[ij];
        goto Label5;
    Label4:
        a[l] = a[k];
        a[k] = tt;
        goto Label5;
    Label5:
        l--;
        if (a[l] > t)
            goto Label5;
        tt = a[l];
        goto Label6;
    Label6:
        k++;
        if (a[k] < t)
            goto Label6;
        if (k <= l)
            goto Label4;
        if (l - i <= j - k)
            goto Label7;
        il[m] = i;
        iu[m] = l;
        i = k;
        m++;
        goto Label9;
    Label7:
        il[m] = k;
        iu[m] = j;
        j = l;
        m++;
        goto Label9;
    Label8:
        m--;
        if (m == -1)
            return;
        i = il[m];
        j = iu[m];
        goto Label9;
    Label9:
        if (j - i > 10)
            goto Label2;
        if (i == ii)
            goto Label1;
        i--;
        goto Label10;
    Label10:
        i++;
        if (i == j)
            goto Label8;
        t = a[i + 1];
        if (a[i] <= t)
            goto Label10;
        k = i;
        goto Label11;
    Label11:
        a[k + 1] = a[k];
        k--;
        if (t < a[k])
            goto Label11;
        a[k + 1] = t;
        goto Label10;
}

void Sorting::SingletonsSort(long long a[], int n)
{
    DoSingletonsSort(a, 0, n - 1);
}

void Sorting::SiftUp(long long a[], int i, int n)
{
    long long copy = a[i];
    int j;

    while (true)
    {
        j = i + i;

        if (j <= n)
        {
            if (j < n)
            {
                if (a[j + 1] > a[j])
                    j++;
            }

            if (a[j] > copy)
            {
                a[i] = a[j];
                i = j;
                continue;
            }
        }

        break;
    }

    a[i] = copy;
}

void Sorting::TreeSort3(long long a[], int n)
{
    for (int i = n / 2; i >= 1; i--)
        SiftUp(a, i, n - 1);

    for (int i = n - 1; i >= 1; i--)
    {
        SiftUp(a, 0, i);

        long long t = a[0];

        a[0] = a[i];
        a[i] = t;
    }
}

void Sorting::CountingSort(
    long long A[],
    long long B[],
    long long C[],
    int n, long long k)
{
    for (long long i = 0; i <= k; i++)
        C[i] = 0;

    for (int j = 0; j < n; j++)
    {
        B[j] = 0;
        C[A[j]]++;
    }

    for (long long i = 1; i <= k; i++)
        C[i] += C[i - 1];

    for (int i = n - 1; i >= 0; i--)
    {
        long long j = A[i];

        C[j]--;
        B[C[j]] = A[i];
    }
}
#pragma once
#include <limits.h>
#include <vector>
using namespace std;

class SampleStatistics {
public:
	inline static long long Mean(vector<long long> x) {
		long long sum = 0;

		for (int i = 0; i < (int)x.size(); i++)
			sum += (long long)x[i];

		return sum / (int)x.size();
	};
	inline static long long Max(vector<long long> x)
	{
		long long max = LLONG_MIN;

		for (int i = 0; i < (int)x.size(); i++)
			if (x[i] > max)
				max = x[i];

		return max;
	};
	inline static long long Min(vector<long long> x)
	{
		long long min = LLONG_MAX;

		for (int i = 0; i < (int)x.size(); i++)
			if (x[i] < min)
				min = x[i];

		return min;
	};
	inline static long long Median(vector<long long> x)
	{
		unsigned int n0 = (unsigned int)x.size();
		unsigned int n1 = n0 / 2 - 1;
		unsigned int n2 = n0 / 2;
		long long median = 0, lt = x[n1], rt = x[n2];

		if ((n0 & 1) == 1)
			median = x[n0 / 2];
		else
			median = (lt + rt) / 2;

		return median;
	};
	inline static long long Variance(vector<long long> x)
	{
		long long mean = Mean(x), sumSq = 0;
		int n = (int)x.size();
		int n1 = n - 1;

		for (int i = 0; i < n; i++)
		{
			long long delta = x[i] - mean;

			sumSq += delta * delta;
		}

		return sumSq / n1;
	};
};
#include "SampleStatistics.h"
#include "Sorting.h"
#include <stdlib.h>
#include <algorithm>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std::chrono;
using namespace std;

// https://www.geeksforgeeks.org/measure-execution-time-function-cpp/

int GetSubOption(char title[])
{
	char line[128];
	cout << title << endl;
	cout << "1 Basic Exchange" << endl;
	cout << "2 Standard Exchange" << endl;
	cout << "3 Insertion Sort" << endl;
	cout << "4 Selection Sort" << endl;
	cout << "5 Simple Sifting (Shuttle Sort)" << endl;
	cout << "6 Shell Sort" << endl;
	cout << "7 Heap Sort" << endl;
	cout << "8 Quick Sort" << endl;
	cout << "9 Singleton's Sort" << endl;
	cout << "10 Tree Sort 3" << endl;
	cout << "11 Counting Sort" << endl;
	cout << "12 Exit Submenu" << endl;
	cout << "13 Exit Program" << endl;
	cout << "Suboption Number: ";
	cin.getline(line, 128);

	int so = 0;
	if (strlen(line) > 1)
	{
		so = 10 * (line[0] - '0');
		so += line[1] - '0';
	}

	else
		so = line[0] - '0';
	
	return so;
}

int DoSort(char option) {
	char line[128];
	char title[128] = { 0 };
	char name[11][64] = { { 0 } };
	int subOption;

	strcpy_s(name[0], 64, "Basic Exchange");
	strcpy_s(name[1], 64, "Standard Exchange");
	strcpy_s(name[2], 64, "Insertion Sort");
	strcat_s(name[3], 64, "Selection Sort");
	strcpy_s(name[4], 64, "Simple Shifting");
	strcpy_s(name[5], 64, "Shell Sort");
	strcat_s(name[6], 64, "Heap Sort");
	strcat_s(name[7], 64, "Quick Sort");
	strcat_s(name[8], 64, "Singleton's Sort");
	strcat_s(name[9], 64, "Tree Sort 3");
	strcpy_s(name[10], 64, "Counting Sort");

	vector<long long> runtime;
	
	if (option == '1')
	{
		strcpy_s(title, 128, "Single Sorting Tests Submenu");
	}
	else {
		strcpy_s(title, 128, "Statistical Sorting Tests Submenu");
	}

	subOption = GetSubOption(title);
	
	if (subOption < 1 || subOption > 13)
	{
		cout << "Illegal Suboption Exiting Application!" << endl;
		exit(-1);
	}

	if (subOption == 12)
		return subOption;
	
	if (subOption == 13)
		exit(1);

	int index = subOption - 1, maximum = 0, n = 0, seed = 1;

	cout << name[index] << endl;

	do {
		cout << "PRNG Seed             = ";
		cin.getline(line, 128);
		seed = atoi(line);
	} while (seed < 1);

	do {
		cout << "Number of Samples     = ";
		cin.getline(line, 128);
		n = atoi(line);
	} while (n < 2);

	do {
		cout << "Maximum Sample Value  = ";
		cin.getline(line, 128);
		maximum = atoi(line);
	} while (maximum < 10);

	srand(seed);

	int number = 0;
	
	if (option == '2')
	{
		do {
			cout << "Number of Experiments = ";
			cin.getline(line, 128);
			number = atoi(line);
		} while (number < 1);
	}

	else
	{
		number = 1;
	}
	
	long long k = 0;
	long long* B = new long long[n];
	long long* sample = new long long[n];
	long long* shadow = new long long[n];

	for (int i = 0; i < number; i++)
	{
		long long* C = NULL;

		for (int j = 0; j < n; j++)
		{
			sample[j] = rand() % maximum;

			if (option == '1') {
				shadow[j] = sample[j];
			}
		}

		if (subOption == 11)
		{
			for (int j = 0; j < n; j++)
				if (sample[j] > k)
					k = sample[j];

			C = new long long[(unsigned int)(k + 1)];
		}
		
		auto start = high_resolution_clock::now();

		switch (subOption) {
		case 1:
			Sorting::BasicExchange(sample, n);
			break;
		case 2:
			Sorting::StandardExchange(sample, n);
			break;
		case 3:
			Sorting::InsertionSort(sample, n);
			break;
		case 4:
			Sorting::SelectionSort(sample, n);
			break;
		case 5:
			Sorting::SimpleShifting(sample, n);
			break;
		case 6:
			Sorting::ShellSort(sample, n);
			break;
		case 7:
			Sorting::HeapSort(sample, n);
			break;
		case 8:
			Sorting::QuickSort(sample, n);
			break;
		case 9:
			Sorting::SingletonsSort(sample, n);
			break;
		case 10:
			Sorting::TreeSort3(sample, n);
			break;
		case 11:		
			Sorting::CountingSort(sample, B, C, n, k);
			break;
		default:
			cout << "Unknown Suboption" << endl;
			break;
		}

		auto stop = high_resolution_clock::now();
		auto duration = duration_cast<microseconds>(stop - start);
		long long rt = (long long)duration.count();

		runtime.push_back(rt);

		if (subOption == 11)
		{
			if (C != NULL)
				delete[] C;
		}
	}

	if (option == '1')
	{
		for (int i = 0; i < n; i++)
		{
			cout << setw(2) << shadow[i] << ' ';
			if (subOption != 11)
				cout << setw(2) << sample[i] << endl;
			else
				cout << setw(2) << B[i] << endl;
		}
	}
	
	else if (option == '2') {
		sort(runtime.begin(), runtime.end());

		cout << "Runtimes in Microseconds" << endl;

		if (runtime.size() <= 15)
		{
			for (int i = 0; i < (int)runtime.size(); i++)
				cout << setw(4) << runtime[i] << endl;
		}

		cout << "Minimum Runtime       = " 
			<< setw(4) << fixed << setprecision(0)
			<< SampleStatistics::Min(runtime) << endl;
		cout << "Maximum Runtime       = " 
			<< setw(4) << fixed << setprecision(0)
			<< SampleStatistics::Max(runtime) << endl;
		cout << "Mean Runtime          = " 
			<< setw(4) << fixed << setprecision(0)
			<< SampleStatistics::Mean(runtime) << endl;
		cout << "Median Runtime        = "
			<< setw(4) << fixed << setprecision(0) <<
			SampleStatistics::Median(runtime) << endl;
	}

	delete[] B;
	delete[] sample;
	delete[] shadow;
	
	return subOption;
}

int main() {
	while (true) {
		char line[128];

		cout << "Menu" << endl;
		cout << "1 Single Sorting Tests" << endl;
		cout << "2 Statistical Tests" << endl;
		cout << "3 Exit" << endl;;
		cout << "Option number: ";
		cin.getline(line, 128);

		if (line[0] == '3')
			break;

		if (line[0] == '1' || line[0] == '2') {
			while (true)
			{
				int doSort = DoSort(line[0]);

				if (doSort == 12)
					break;
				else if (doSort == 13)
					exit(1);
			}
		}
	}

	return 0;
}

New Sorting Results by James Pate Wiliams, Jr.

My sorting application now supports eleven sorting algorithms. Below are some results from ten of the methods.

Basic Exchange
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 134039
Maximum Runtime       = 143654
Mean Runtime          = 137164
Median Runtime        = 136788

Standard Exchange
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 318753
Maximum Runtime       = 389181
Mean Runtime          = 330273
Median Runtime        = 328034

Insertion Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 48089
Maximum Runtime       = 54204
Mean Runtime          = 49308
Median Runtime        = 49116

Selection Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 224979
Maximum Runtime       = 348275
Mean Runtime          = 233022
Median Runtime        = 229386

Simple Shifting
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 115351
Maximum Runtime       = 131739
Mean Runtime          = 117297
Median Runtime        = 116714

Heap Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       = 2408
Maximum Runtime       = 2800
Mean Runtime          = 2477
Median Runtime        = 2454


Quick Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       =  838
Maximum Runtime       = 1011
Mean Runtime          =  900
Median Runtime        =  893

Singleton's Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       =  727
Maximum Runtime       =  849
Mean Runtime          =  761
Median Runtime        =  747

Counting Sort
PRNG Seed             = 1
Number of Samples     = 10000
Maximum Sample Value  = 10000
Number of Experiments = 100
Runtimes in Microseconds
Minimum Runtime       =   97
Maximum Runtime       =  122
Mean Runtime          =  103
Median Runtime        =  103

Hamiltonian Circuit (Cycle) by James Pate Williams, Jr.

namespace HamiltonianCircuit
{
    class Algorithm
    {
        // code from C/C++
        // http://www.geeksforgeeks.org/backtracking-set-7-hamiltonian-cycle/

        // A utility function to check if the vertex v can be added at
        // index 'pos' in the Hamiltonian Cycle constructed so far (stored
        // in 'path[]')

        private bool IsSafe(int v, bool[,] graph, int[] path, int pos)
        {
            /* Check if this vertex is an adjacent vertex of the previously
               added vertex. */
            if (!graph[path[pos - 1], v])
                return false;

            /* Check if the vertex has already been included.
              This step can be optimized by creating an array of size V */
            for (int i = 0; i < pos; i++)
                if (path[i] == v)
                    return false;

            return true;
        }

        /* A recursive utility function to solve hamiltonian cycle problem */
        private bool HamCycleUtil(bool[,] graph, int V, int[] path, int pos)
        {
            /* base case: If all vertices are included in Hamiltonian Cycle */
            if (pos == V)
            {
                // And if there is an edge from the last included vertex to the
                // first vertex
                if (graph[path[pos - 1], path[0]])
                    return true;
                else
                    return false;
            }

            // Try different vertices as a next candidate in Hamiltonian Cycle.
            // We don't try for 0 as we included 0 as starting point in in hamCycle()
            for (int v = 1; v < V; v++)
            {
                // Check if this vertex can be added to Hamiltonian Cycle

                if (IsSafe(v, graph, path, pos))
                {
                    path[pos] = v;

                    // recur to construct rest of the path

                    if (HamCycleUtil(graph, V, path, pos + 1))
                        return true;

                    // If adding vertex v doesn't lead to a solution,
                    // then remove it
                    path[pos] = -1;
                }
            }

            // If no vertex can be added to Hamiltonian Cycle constructed so far,
            // then return false
            return false;
        }

        // This function solves the Hamiltonian Cycle problem using Backtracking.
        // It mainly uses HamCycleUtil() to solve the problem. It returns false
        // if there is no Hamiltonian Cycle possible, otherwise return true and
        // prints the path. Please note that there may be more than one solutions,
        // this function prints one of the feasible solutions.
        public bool HamCycle(bool[,] graph, int V, out int[] path)
        {
            path = new int[V];

            for (int i = 0; i < V; i++)
                path[i] = -1;

           // Let us put vertex 0 as the first vertex in the path. If there is
           // a Hamiltonian Cycle, then the path can be started from any point
           // of the cycle as the graph is undirected

            path[0] = 0;

            if (HamCycleUtil(graph, V, path, 1) == false)
                return false;

            return true;
        }

    }
}
using System;
using System.Collections.Generic;

namespace HamiltonianCircuit
{
    class Edge : IComparable
    {
        public Vertex Lt { get; set; }
        public Vertex Rt { get; set; }
        public int Wt { get; set; }
        public Edge(Vertex lt, Vertex rt, int wt)
        {
            Lt = lt;
            Rt = rt;
            Wt = wt;
        }

        public int CompareTo(object obj)
        {
            Edge other = (Edge)obj;
            int c1 = Lt.CompareTo(other.Lt);
            int c2 = Rt.CompareTo(other.Rt);

            if (c1 != 0)
                return c1;

            if (c2 != 0)
                return c2;

            return Wt - other.Wt;
        }

        public bool InList(List<Edge> elist)
        {
            for (int i = 0; i < elist.Count; i++)
            {
                Edge e = elist[i];

                if (Lt == e.Lt && Rt == e.Rt)
                    return true;
            }

            return false;
        }
    }
}
using System;
using System.Collections.Generic;

namespace HamiltonianCircuit
{
    class Vertex : IComparable
    {
        public int Id { get; set; }
        public List<Edge> Edges { get; set; }
        public Vertex(int id)
        {
            Id = id;
        }

        public Vertex(int id, List<Edge> edges)
        {
            Id = id;
            Edges = edges;
        }

        public int CompareTo(object obj)
        {
            Vertex other = (Vertex)obj;

            return Id - other.Id;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace HamiltonianCircuit
{
    public partial class MainForm : Form
    {
        private bool generate = true;
        private int n, x, y, x1, y1, x2, y2;
        private Algorithm algo = new Algorithm();
        private Color[] colors =
            {
            Color.Red,
            Color.Blue,
            Color.Green,
            Color.Orange,
            Color.Purple,
            Color.Brown,
            Color.Turquoise,
            Color.Violet,
            Color.Tan,
            Color.Plum,
            Color.Teal,
            Color.Yellow
            };
        private List<Edge> E, F;
        private List<Vertex> V;
        private Random random = new Random();
        private SolidBrush drawBrush;
        private Font drawFont;
        public MainForm()
        {
            InitializeComponent();
            panel1.Paint += new PaintEventHandler(panel1_Paint);
            drawBrush = new SolidBrush(Color.White);
        }

        void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (generate)
                GenerateDraw(e.Graphics);

            else
                PathDraw(e.Graphics);
        }

        private void calculateXY(int id)
        {
            int Width = panel1.Width;
            int Height = panel1.Height;

            x = Width / 2 + (int)(Width * Math.Cos(2 * id * Math.PI / n) / 4.0);
            y = Height / 2 + (int)(Width * Math.Sin(2 * id * Math.PI / n) / 4.0);
        }

        private void PathDraw(Graphics g)
        {
            if (V != null)
            {
                GenerateDraw(g);

                int divisor = 1;
                int Width = panel1.Width;
                int Height = panel1.Height;
                Pen pen = new Pen(Color.Red);

                n = V.Count;

                for (int i = 0; i < F.Count; i++)
                {
                    Vertex u = F[i].Lt, v = F[i].Rt;

                    calculateXY(u.Id);
                    x1 = x + (Width / 2) / n / 2;
                    y1 = y + (Width / 2) / n / 2;
                    calculateXY(v.Id);
                    x2 = x + (Width / 2) / n / 2;
                    y2 = y + (Width / 2) / n / 2;
                    g.DrawLine(pen, x1, y1, x2, y2);
                }

                if (n >= 4 && n <= 5)
                    divisor = 16;
                else if (n >= 6 && n <= 8)
                    divisor = 24;
                else if (n >= 9 && n <= 10)
                    divisor = 32;

                drawFont = new Font("Arial", Width / divisor);

                for (int i = 0; i < n; i++)
                {
                    Vertex u = V[i];
                    SolidBrush brush = new SolidBrush(colors[u.Id]);

                    calculateXY(u.Id);
                    g.FillEllipse(brush, x, y, (Width / 2) / n, (Width / 2) / n);

                    if (n >= 4 && n <= 10)
                        g.DrawString(i.ToString(), drawFont, drawBrush, x + 4, y + 4);
                }
            }
        }

        private void GenerateDraw(Graphics g)
        {
            if (V != null)
            {
                int divisor = 1;
                int Width = panel1.Width;
                int Height = panel1.Height;
                Pen pen = new Pen(Color.Black);

                n = V.Count;

                for (int i = 0; i < n; i++)
                {
                    Vertex u = V[i];

                    calculateXY(u.Id);
                    x1 = x + (Width / 2) / n / 2;
                    y1 = y + (Width / 2) / n / 2;

                    if (u.Edges != null)
                    {
                        for (int j = 0; j < u.Edges.Count; j++)
                        {
                            Vertex v = u.Edges[j].Rt;

                            calculateXY(v.Id);
                            x2 = x + (Width / 2) / n / 2;
                            y2 = y + (Width / 2) / n / 2;
                            g.DrawLine(pen, x1, y1, x2, y2);
                        }
                    }
                }

                if (n >= 4 && n <= 5)
                    divisor = 16;
                else if (n >= 6 && n <= 8)
                    divisor = 24;
                else if (n >= 9 && n <= 10)
                    divisor = 32;

                drawFont = new Font("Arial", Width / divisor);

                for (int i = 0; i < n; i++)
                {
                    Vertex u = V[i];
                    SolidBrush brush = new SolidBrush(colors[u.Id]);

                    calculateXY(u.Id);
                    g.FillEllipse(brush, x, y, (Width / 2) / n, (Width / 2) / n);
                    
                    if (n >= 4 && n <= 10)
                        g.DrawString(i.ToString(), drawFont, drawBrush, x + 4, y + 4);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            generate = true;
            button2.Enabled = true;

            int numVers = (int)numericUpDown1.Value;

            E = new List<Edge>();
            V = new List<Vertex>();

            for (int i = 0; i < numVers; i++)
            {
                Vertex v = new Vertex(i);

                v.Edges = new List<Edge>();
                V.Add(v);
            }

            for (int i = 0; i < numVers; i++)
            {
                int numEdges = random.Next(numVers - 1);

                while (numEdges < 2)
                    numEdges = random.Next(numVers - 1);

                Vertex v = V[i];

                for (int j = 0; j < numEdges; j++)
                {
                    int id = random.Next(numVers);
                    int wt = random.Next(100);
                    Edge edge;

                    while (wt < 10)
                        wt = random.Next(100);

                    while (id == v.Id)
                        id = random.Next(numVers);

                    edge = new Edge(v, V[id], wt);

                    if (!edge.InList(E))
                        E.Add(edge);

                    edge = new Edge(V[id], v, wt);

                    if (!edge.InList(E))
                        E.Add(edge);
                }
            }

            for (int i = 0; i < E.Count; i++)
            {
                Vertex u = E[i].Lt, v = E[i].Rt;

                u.Edges.Add(new Edge(u, v, E[i].Wt));
                v.Edges.Add(new Edge(v, u, E[i].Wt));
            }

            for (int i = 0; i < V.Count; i++)
            {
                if (V[i].Edges.Count == 0)
                {
                    MessageBox.Show("Generate a new graph", "Warning Message",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
            }

            textBox1.Text = string.Empty;
            textBox1.Text = "Edges(u, v)\r\n";
            textBox1.Text += " u  v wt\r\n";

            for (int i = 0; i < E.Count; i++)
            {
                textBox1.Text += E[i].Lt.Id.ToString().PadLeft(2) + " ";
                textBox1.Text += E[i].Rt.Id.ToString().PadLeft(2) + " ";
                textBox1.Text += E[i].Wt.ToString().PadLeft(2) + "\r\n";
            }

            panel1.Invalidate();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            generate = false;

            Algorithm algo = new Algorithm();

            int n = V.Count;
            bool[,] graph = new bool[n, n];
            int[] ipath;

            for (int i = 0; i < E.Count; i++)
            {
                Edge edge = E[i];
                Vertex u = edge.Lt, v = edge.Rt;

                graph[u.Id, v.Id] = true;
            }

            if (!algo.HamCycle(graph, n, out ipath))
            {
                MessageBox.Show("No Hamilton circuit exists", "Warning Message",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            textBox1.Text += "\r\n";
            textBox1.Text += "Edges(u, v)\r\n";
            textBox1.Text += " u  v wt\r\n";

            Vertex[] path = new Vertex[n];
            int tcost = 0;

            F = new List<Edge>();

            for (int i = 0; i < n - 1; i++)
            {
                Vertex u = V[ipath[i]], v = V[ipath[i + 1]];
                Edge edge = new Edge(u, v, 0);

                for (int j = 0; j < E.Count; j++)
                {
                    if (edge.Lt == E[j].Lt && edge.Rt == E[j].Rt)
                    {
                        edge.Wt = E[j].Wt;
                        tcost += edge.Wt;
                        break;
                    }
                }

                F.Add(edge);
                textBox1.Text += u.Id.ToString().PadLeft(2) + " ";
                textBox1.Text += v.Id.ToString().PadLeft(2) + " ";
                textBox1.Text += edge.Wt.ToString().PadLeft(2) + "\r\n";
            }

            Vertex up = V[ipath[n - 1]], vp = V[0];

            Edge edgep = new Edge(up, vp, 0);

            for (int j = 0; j < E.Count; j++)
            {
                if (edgep.Lt == E[j].Lt && edgep.Rt == E[j].Rt)
                {
                    edgep.Wt = E[j].Wt;
                    tcost += edgep.Wt;
                    break;
                }
            }

            F.Add(edgep);
            textBox1.Text += up.Id.ToString().PadLeft(2) + " ";
            textBox1.Text += vp.Id.ToString().PadLeft(2) + " ";
            textBox1.Text += edgep.Wt.ToString().PadLeft(2) + "\r\n";

            textBox1.Text += "Cost = " + tcost + "\r\n";
            panel1.Invalidate();
        }
    }
}
Hamiltonian for a Four Node Graph
Hamiltonian for a Five Node Graph
Hamiltonian for a Six Node Graph