/*
http://home.attbi.com/~fbkotler/nasmdoc0.html


use 2 masks for odd/even mobility
a1-b1
46666 solutions in 1389029 nodes in 62 ticks (148174528 cycles)
*/
#include <stdio.h>

#define SHL 0
#define NASM 0
#define FASM 1
#define MASM 0
#define PARTS 0 	// 0=one file containing all routines, 1=multiple files
#define USE_DEC 0	// 0=no DEC/INC, 1=DEC/INC

#define N 8
#define OFFSET(x,y) ((y)*N+(x))
#define OFFSET_MOBILITY (N*N*4/2)	// points in the middle of the table !!!

#define MAGIC 1
#define ALIGN 16
#define NBVERTICES (N*N)
#define GETPARITY(x,y) (((x)+(y))&1)
#define PARITY(o) GETPARITY(GETX(o), GETY(o))
#define GETX(offset) ((offset)%N)
#define GETY(offset) ((offset)/N)
#define NPARITY PARITY(START_SQUARE)	// generate code for white/black square (0=white, 1=black)

#define Rcount	"eax"
#define Rcountl "al"
#define Scratch1	"dl"
#define Scratch2	"cl"
#define Rnum	"edi"
#define Rmobility "esi"
#define RMagic	"ebp"
#if MASM
#define OffsetMagic "offset LowerBounds"
#define dword "dword ptr "
#else
#define OffsetMagic "LowerBounds"
#define dword "dword "
#endif

#define Offset_hsum		(-N*4*4)
#define Offset_vsum		(-N*4*3)
#define Offset_hcount		(-N*4*2)
#define Offset_vcount		(-N*4)
#define Offset_LowerBounds	0
#define Offset_HigherBounds	(ALIGN*4)

static int Graph[NBVERTICES][8];
static FILE *stream;
static FILE *stream2;
static int CountLabel=0;
int Routine;

int START_SQUARE;
int END_SQUARE;

// generates the name of the routine, for a given offset
char *GetName2()
{
	static char name[100];
	sprintf(name, "%c%d-%c%d",
		START_SQUARE/N+'a', (START_SQUARE%N)+1,
		END_SQUARE/N+'a', (END_SQUARE%N)+1
		);
	return name;    
}

static char *GetName(int offset)
{
	static char name[16];
	sprintf(name, "%c%c_%d", GETX(offset)+'a', GETY(offset)+'1', Routine);
	return name;
}

char *String(int n)
{
	static char tmp[256];
	if (n < 0)
	{
		sprintf(tmp, "%d", n);
	}
	else
	{
		sprintf(tmp, "+%d", n);
	}
	return tmp;
}

static void GenSquares()
{
	int offset;
	int n, d;
	int d2;
	int o, o2;
	int first;
#if PARTS
	char filename[256];
#endif

	fprintf(stream2, "{Compute%d,\"%s\"},\n", Routine, GetName2());

#if PARTS
	sprintf(filename, "CODE%d.ASM", Routine);

	stream = fopen(filename, "wt");
#if NASM
	fprintf(stream, "\tCPU 686\n");
	fprintf(stream, "\tsection .code\n");
	fprintf(stream, "\textern mobility\n");
	fprintf(stream, "\textern _Knight\n");
	fprintf(stream, "\textern _Nodes\n");
	fprintf(stream, "\textern _SaveSolution\n");
#endif
#if FASM
	fprintf(stream, "format MS COFF\n");
	fprintf(stream, "\tsection '.text' code readable executable\n");
	fprintf(stream, "\textrn mobility\n");
	fprintf(stream, "\textrn _Knight\n");
	fprintf(stream, "\textrn _Nodes\n");
	fprintf(stream, "\textrn _SaveSolution\n");
	fprintf(stream, "SECTION_START:\n");
	fprintf(stream, "macro align Alignment {\n");
	fprintf(stream, "\tREPEAT (Alignment-1)-(($-SECTION_START+Alignment-1) mod Alignment)\n");
	fprintf(stream, "\tret\n");
	fprintf(stream, "\tEND REPEAT\n");
	fprintf(stream, "}\n");
#endif
#if MASM
	fprintf(stream, ".586P\n");
	fprintf(stream, ".MODEL FLAT\n");
	fprintf(stream, "\t.code\n");
	fprintf(stream, "\textrn mobility:dword\n");
	fprintf(stream, "\textrn _Knight:dword\n");
	fprintf(stream, "\textrn _Nodes:dword\n");
	fprintf(stream, "\textrn _SaveSolution:near\n");
#endif
#endif

	fprintf(stream, "\talign 16\n");
#if NASM
	fprintf(stream, "\tglobal _Compute%d\n", Routine);
#endif
#if MASM||FASM
	fprintf(stream, "\tpublic _Compute%d\n", Routine);
#endif
	fprintf(stream, ";%s\n", GetName2());
	fprintf(stream, "_Compute%d:\n", Routine);
	fprintf(stream, "\tpusha\n");
#if MAGIC
	fprintf(stream, "\tmov %s,%s\n", RMagic, OffsetMagic);
#endif
	fprintf(stream, "\tmov %s,-1\n", Rcount/*, Rcount*/);
	fprintf(stream, "\tmov %s,1\n", Rnum);
	fprintf(stream, "\tmov %s,mobility+%d\n", Rmobility, OFFSET_MOBILITY);
	fprintf(stream, "\tcall %s\n", GetName(START_SQUARE));
	fprintf(stream, "\tpopa\n");
	fprintf(stream, "\tret\n");
				
	fprintf(stream, "sol%s:\n", GetName(START_SQUARE));
	fprintf(stream, "\tpusha\n");
	fprintf(stream, "\tmov %s[_Knight+%d*4], %d\n", dword, N*N-1, END_SQUARE);
	fprintf(stream, "\txor ebx, ebx\n");
	n=0;
	for (d=0;d<8;++d)
	{
		o=Graph[END_SQUARE][d];
		if (o<0) break;
		fprintf(stream, "\ttest eax, [%s%s]\n", Rmobility, String(o*4-OFFSET_MOBILITY));
		fprintf(stream, "\tjs no%s%d\n", GetName(START_SQUARE), d);
		fprintf(stream, "\tmov ebx,%d\n", o);
		fprintf(stream, "no%s%d:\n", GetName(START_SQUARE), d);
	}
	fprintf(stream, "\tmov [_Knight+%d*4], ebx\n", N*N-2);
	fprintf(stream, "\tcall _SaveSolution\n");
	fprintf(stream, "\tpopa\n");
	
	for (offset = 0;offset < NBVERTICES;++offset)
	{
		if (offset == END_SQUARE) continue;
#if MAGIC
		fprintf(stream, "ret%s:\n", GetName(offset));
#endif
		fprintf(stream, "\tret\n");

		fprintf(stream, "\talign 16\n");
		fprintf(stream, "%s:\n", GetName(offset));
		fprintf(stream, "\tadd %s[_Nodes-8+%s*8],1\n", dword, Rnum);
		fprintf(stream, "\tmov %s[_Knight-4+%s*4],%d\n", dword, Rnum, offset);
		fprintf(stream, "\tadc %s[_Nodes-8+4+%s*8],0\n", dword, Rnum);
		n=0;
		for (d=0;d<8;++d)
		{
			o=Graph[offset][d];
			if (o<0) break;
			for (d2=0;d2<8;++d2)
			{
				o2=Graph[o][d2];
				if (o2 < 0) break;
				if (o2 == END_SQUARE)
				{
					n=1;
				}
			}
		}
		if (n)
		{
			fprintf(stream, "\tcmp %s,%d\n", Rnum, NBVERTICES-2);
			fprintf(stream, "\tje sol%s\n", GetName(START_SQUARE));
		}
		
#if MAGIC
		fprintf(stream, "\tmov ebx, [%s+%d]\n", RMagic, GETY(offset)*4+Offset_hsum);
		fprintf(stream, "\tmov edx, [%s+%d]\n", RMagic, GETY(offset)*4+Offset_hcount);
		fprintf(stream, "\tadd ebx, %s\n", Rnum);
		fprintf(stream, "\tcmp ebx, [%s+%d+edx*4]\n", RMagic, 4+Offset_LowerBounds);
		fprintf(stream, "\tjb ret%s\n", GetName(offset));

#if SHL
		fprintf(stream, "\tmov ecx, %s\n", Rnum);
		fprintf(stream, "\tshl ecx, 6\n");
#else
		fprintf(stream, "\tlea ecx, [%s*8]\n", Rnum);
		fprintf(stream, "\tlea ecx, [ecx*8+%s+%d]\n", RMagic, Offset_HigherBounds);
#endif

#if SHL
		fprintf(stream, "\tcmp ebx, [HigherBounds+edx*4+%d+ecx]\n", (ALIGN*2+1)*4);
#else
		fprintf(stream, "\tcmp ebx, [edx*4+%d+ecx]\n", (ALIGN*2+1)*4);
#endif
		fprintf(stream, "\tja ret%s\n", GetName(offset));
				
		// now the vertical sums
		fprintf(stream, "\tmov ebx, [%s+%d]\n", RMagic, GETX(offset)*4+Offset_vsum);
		fprintf(stream, "\tmov edx, [%s+%d]\n", RMagic, GETX(offset)*4+Offset_vcount);
		fprintf(stream, "\tadd ebx, %s\n", Rnum);
		fprintf(stream, "\tcmp ebx, [%s+%d+edx*4]\n", RMagic, 4+Offset_LowerBounds);
		fprintf(stream, "\tjb ret%s\n", GetName(offset));
#if SHL
		fprintf(stream, "\tcmp ebx, [HigherBounds+edx*4+%d+ecx]\n", (ALIGN*2+1)*4);
#else
		fprintf(stream, "\tcmp ebx, [edx*4+%d+ecx]\n", (ALIGN*2+1)*4);
#endif
		fprintf(stream, "\tja ret%s\n", GetName(offset));

		// horizontal sums
		for (d = 0;d < N;++d)
		{
			if (d==GETY(offset)) continue;
			fprintf(stream, "\tmov edx, [%s+%d]\n", RMagic, Offset_hcount+d*4);
			fprintf(stream, "\tmov ebx, [%s+%d]\n", RMagic, Offset_hsum+d*4);
#if SHL
			fprintf(stream, "\tcmp ebx, [HigherBounds+edx*4+ecx]\n");
#else
			fprintf(stream, "\tcmp ebx, [edx*4+ecx]\n");
#endif
			fprintf(stream, "\tja ret%s\n", GetName(offset));
			
		}

		// vertical sums
		for (d = 0;d < N;++d)
		{
			if (d==GETX(offset)) continue;
			fprintf(stream, "\tmov edx, [%s+%d]\n", RMagic, Offset_vcount+d*4);
			fprintf(stream, "\tmov ebx, [%s+%d]\n", RMagic, Offset_vsum+d*4);
#if SHL
			fprintf(stream, "\tcmp ebx, [HigherBounds+edx*4+ecx]\n");
#else
			fprintf(stream, "\tcmp ebx, [edx*4+ecx]\n");
#endif
			if (offset == END_SQUARE-1)
			{
				fprintf(stream, "\tja ret%s\n", GetName(offset+2));
			}
			else
			{
				fprintf(stream, "\tja ret%s\n", GetName(offset+1));
			}
		}
		fprintf(stream, "\tadd [%s+%d], %s\n", RMagic, Offset_vsum+GETX(offset)*4, Rnum);
		fprintf(stream, "\tadd [%s+%d], %s\n", RMagic, Offset_hsum+GETY(offset)*4, Rnum);
		fprintf(stream, "\tadd %s[%s+%d], 1\n", dword, RMagic, Offset_hcount+GETY(offset)*4);
		fprintf(stream, "\tadd %s[%s+%d], 1\n", dword, RMagic, Offset_vcount+GETX(offset)*4);
#endif

		// decrement the mobility of all adjacent squares
		o2=0;
		n=0;
		first=-1;
		for(d=0;d<8;++d)
		{
			o=Graph[offset][d];
			if (o<0) break;
			if (o == START_SQUARE) continue;
			if (o == END_SQUARE)
			{
#if USE_DEC
				fprintf(stream, "\tdec %s[%s%s]\n", dword, Rmobility, String(o*4-OFFSET_MOBILITY));
#else
				fprintf(stream, "\tsub %s[%s%s],1\n", dword, Rmobility, String(o*4-OFFSET_MOBILITY));
#endif
				o2=1;
			}
			else
			{
				if (n)
				{
#if USE_DEC
					fprintf(stream, "\tdec %s[%s%s]\n", dword, Rmobility, String(o*4-OFFSET_MOBILITY));
#else
					fprintf(stream, "\tsub %s[%s%s],1\n", dword, Rmobility, String(o*4-OFFSET_MOBILITY));
#endif
					if (n&1)
					{
						fprintf(stream, "\tsete %s\n", Scratch1);
						if (n>1)
						{
							fprintf(stream, "\tadd %s,%s\n", Rcountl, Scratch2);
						}
					}
					else
					{
						fprintf(stream, "\tsete %s\n", Scratch2);
						if (n>1)
						{
							fprintf(stream, "\tadd %s,%s\n", Rcountl, Scratch1);
						}
					}
				}
				else
				{
					
					fprintf(stream, "\tmov ebx,[%s%s]\n", Rmobility, String(o*4-OFFSET_MOBILITY));
					fprintf(stream, "\tpush %s\n", Rcount);
#if USE_DEC
					fprintf(stream, "\tdec ebx\n");
#else
					fprintf(stream, "\tsub ebx,1\n");
#endif
					fprintf(stream, "\tsete %s\n", Rcountl);
					first=o;
				}
				++n;
			}
		}
		if (n>1)
		{
			if (n&1)
			{
				fprintf(stream, "\tadd %s,%s\n", Rcountl, Scratch2);
			}
			else
			{
				fprintf(stream, "\tadd %s,%s\n", Rcountl, Scratch1);
			}
		}
		
		fprintf(stream, "\ttest %s,-2\n", Rcountl);
		fprintf(stream, "\tjne skip%s\n", GetName(offset));
		
		fprintf(stream, "\tsub %s[%s%s],8\n", dword, Rmobility ,String(offset*4-OFFSET_MOBILITY));
		fprintf(stream, "\tneg al\n"/*, Rcountl*/);

		n=0;
		for(d=0;d<8;++d)
		{
			o=Graph[offset][d];
			if (o < 0) break;
			if (o == START_SQUARE)
			{
				continue;
			}
			
			if (o == END_SQUARE)
			{
				continue;
			}

			if (!n)
			{
				fprintf(stream, "\tmov [%s%s],ebx\n", Rmobility,String(o*4-OFFSET_MOBILITY));
#if USE_DEC
				fprintf(stream, "\tinc %s\n", Rnum);
#else
				fprintf(stream, "\tadd %s,1\n", Rnum);
#endif
				fprintf(stream, "\ttest eax,ebx\n"/*, o*/);
			}
			else
			{
				fprintf(stream, "\ttest eax,[%s%s]\n", Rmobility,String(o*4-OFFSET_MOBILITY));
			}
			++n;
			fprintf(stream, "\tjne skip%d\n", ++CountLabel);
			
			if (PARITY(offset)!=NPARITY)
			{
				//without: 524486 solutions in 13353465 nodes in 734 ticks
				for (d2=0;d2<8;++d2)
				{
					o2=Graph[o][d2];
					if (o2 < 0) break;
					if (o2 == END_SQUARE)
					{
						fprintf(stream, "\tmov ebx,[%s%s]\n", Rmobility,String(END_SQUARE*4-OFFSET_MOBILITY));
						fprintf(stream, "\ttest ebx,ebx\n"/*, o*/);
						fprintf(stream, "\tje skip%d\n", CountLabel);
					}
				}
			}
			fprintf(stream, "\tcall %s\n", GetName(o));
			fprintf(stream, "skip%d:\n", CountLabel);
		}
		fprintf(stream, "\tadd %s[%s%s],8\n", dword, Rmobility,String(offset*4-OFFSET_MOBILITY));
#if USE_DEC
		fprintf(stream, "\tdec %s\n", Rnum);
#else
		fprintf(stream, "\tsub %s,1\n", Rnum);
#endif
		
		// restores the mobility of all adjacent squares
		if (first < 0) __asm__ ("int $3 "); // YUCK GAS syntax!!!
#if USE_DEC
		fprintf(stream, "\tinc %s[%s%s]\n", dword, Rmobility,String(first*4-OFFSET_MOBILITY));
#else
		fprintf(stream, "\tadd %s[%s%s],1\n", dword, Rmobility,String(first*4-OFFSET_MOBILITY));
#endif
		fprintf(stream, "skip%s:\n", GetName(offset));
		
		for(d=0;d<8;++d)
		{
			o=Graph[offset][d];
			if (o < 0) break;
			if (o == START_SQUARE) continue;
			if (o == first) continue;
#if USE_DEC
			fprintf(stream, "\tinc %s[%s%s]\n", dword, Rmobility,String(o*4-OFFSET_MOBILITY));
#else
			fprintf(stream, "\tadd %s[%s%s],1\n", dword, Rmobility,String(o*4-OFFSET_MOBILITY));
#endif
		}

#if MAGIC
		fprintf(stream, "\tsub [%s+%d], %s\n", RMagic, Offset_vsum+GETX(offset)*4, Rnum);
		fprintf(stream, "\tsub [%s+%d], %s\n", RMagic, Offset_hsum+GETY(offset)*4, Rnum);
		fprintf(stream, "\tsub %s[%s+%d], 1\n", dword, RMagic, Offset_hcount+GETY(offset)*4);
		fprintf(stream, "\tsub %s[%s+%d], 1\n", dword, RMagic, Offset_vcount+GETX(offset)*4);
#endif
		fprintf(stream, "\tpop %s\n", Rcount);
	}
	fprintf(stream, "ret%s:\n", GetName(NBVERTICES));
	fprintf(stream, "\tret\n");
#if PARTS
#if MASM
	fprintf(stream, "\tend\n");
#endif
	fclose(stream);
	stream = NULL;
#endif
}

#define ISVALID(x,y) (x>=0 && x<N && y>=0 && y<N)
static void BuildGraph()
{
	int x, y, d;
	int x2, y2;
	int cnt;
	static int dirs[8][2]={
		{-1,-2},
		{1,-2},
		{-2,-1},
		{2,-1},
		{-2,1},
		{2,1},
		{-1,2},
		{1,2},
	};
	
	for (y=0;y<N;++y)
	{
		for (x=0;x<N;++x)
		{
			cnt=0;

			for (d=0;d<8;++d)
			{
				x2=x+dirs[d][0];
				y2=y+dirs[d][1];
				if (ISVALID(x2, y2))
				{
					Graph[OFFSET(x,y)][cnt]=OFFSET(x2,y2);
					++cnt;
				}
			}
			while(cnt<8)
			{
				Graph[OFFSET(x,y)][cnt]=-1;
				++cnt;
			}
			
		}
	}
}


int Rotation(int n, int rot)
{
	int x, y;
	x = n%N;
	y = n/N;
	
	switch(rot)
	{
	case 0:
		return y*N+x;
	case 1:
		return (N-1-y)*N+x;
	case 2:
		return y*N+(N-1-x);
	case 3:
		return (N-1-y)*N+(N-1-x);
	case 4:
		return x*N+y;
	case 5:
		return (N-1-x)*N+y;
	case 6:
		return x*N+(N-1-y);
	case 7:
		return (N-1-x)*N+(N-1-y);
	}
	return y*N+x;
}

int Symetries[N*N];
int NbSym=0;


void Enumerate()
{
	int start, end;
	int best;
	int r;
	int s1, s2;
	int b1,b2;
	
	for (start=0;start<N*N;++start)
	{
		// computes the symmetries
		best=start;
		for (r=0;r<8;++r)
		{
			s1=Rotation(start, r);
			if (s1<best)
			{
				best = s1;
			}
		}
		if (best < start) continue;
		
		for (end=0;end<N*N;++end)
		{
			if (PARITY(start)==PARITY(end)) continue;
			best = start*64+end;
			for (r=0;r<8;++r)
			{
				s1=Rotation(start, r);
				s2=Rotation(end, r);
				b1 = s1*64+s2;
				b2 = s2*64+s1;
				if (b1 < best) best=b1;
				if (b2 < best) best=b2;
			}
			if (best == start*64+end)
			{
				START_SQUARE = start;
				END_SQUARE = end;

				GenSquares();
				++Routine;                              
			}
		}
	}
}



int main()
{
	int i;
	int n, d;
	int o;
#if MAGIC
	int Values[N+1];
#endif
	BuildGraph();

	//stream = fopen("DATA.ASM", "wt");
	stream = fopen("GEN.ASM", "wt");
	stream2 = fopen("ASM.H", "wt");
#if NASM
	fprintf(stream, "\tCPU 686\n");
#endif
#if FASM
	fprintf(stream, "format MS COFF\n");
#endif
#if MASM
	fprintf(stream, ".586P\n");
	fprintf(stream, ".MODEL FLAT\n");
#endif
	
#if NASM
	fprintf(stream, "\tsection .data\n");
#endif
#if FASM
	fprintf(stream, "\tsection '.data' data readable writeable\n");
#endif
#if MASM
	fprintf(stream, ".data\n");
#endif

	fprintf(stream, "mobility");
	for (o=0;o<NBVERTICES;++o)
	{
		n=0;
		for(d=0;d<8;++d)
		{
			if (Graph[o][d] >= 0) ++n;
		}
		if ((o%N)==0)
		{
			fprintf(stream, "\tdd ");
		}
		else
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "%d",n-1);
		if ((o%N)==N-1)
		{
			fprintf(stream, "\n");
		}
	}
	fprintf(stream, "\n");
#if NASM
	fprintf(stream, "\tglobal _Knight\n");
#endif
#if FASM||MASM
	fprintf(stream, "\tpublic _Knight\n");
#endif

	fprintf(stream, "_Knight");
	for (i=0;i<N*N;++i)
	{
		if ((i % 16) == 0)
		{
			fprintf(stream,"\tdd ");
		}
		else
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0");
		if ((i%16)==15)
		{
			fprintf(stream, "\n");
		}
	}
	fprintf(stream, "\n");
#if NASM
	fprintf(stream, "\tglobal _Nodes\n");
#endif
#if FASM||MASM
	fprintf(stream, "\tpublic _Nodes\n");
#endif
	fprintf(stream, "_Nodes");
	for (n = 0;n<N*N-2;++n)
	{
		if ((n%16)==0)
		{
			fprintf(stream,"\tdd ");
		}
		else
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0,0");
		if ((n%16)==15)
		{
			fprintf(stream,"\n");
		}
	}
	fprintf(stream, "\n");
	
#if MAGIC
#define SUM (N*(N*N+1)/2)
	// first, the lowerbounds, as they are all equal !!!
	
	fprintf(stream, "hsum\tdd ");
	for (n=0;n<N;++n)
	{
		if (n)
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0");
	}
	fprintf(stream, "\n");

	fprintf(stream, "vsum\tdd ");
	for (n=0;n<N;++n)
	{
		if (n)
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0");
	}
	fprintf(stream, "\n");

	fprintf(stream, "hcount\tdd ");
	for (n=0;n<N;++n)
	{
		if (n)
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0");
	}
	fprintf(stream, "\n");
	
	fprintf(stream, "vcount\tdd ");
	for (n=0;n<N;++n)
	{
		if (n)
		{
			fprintf(stream, ",");
		}
		fprintf(stream, "0");
	}
	fprintf(stream, "\n");
	
	
	fprintf(stream, "LowerBounds\tdd ");
	{
		int x;
		// first, the minimum bounds
		n = SUM;
		d = N*N;
		for (x = N;x>=0;--x)
		{
			Values[x]=n;
			n-=d;
			if (n<0) n = 0;
			d-=2;
		}
		for (x = 0;x<=N;++x)
		{
			if (x)
			{
				fprintf(stream, ",");
			}
			fprintf(stream, "%d",Values[x]);
		}
		for (x=N+1;x<ALIGN;++x)
		{
			fprintf(stream, ",-1");
		}
		fprintf(stream, "\n");
	}
	
	fprintf(stream, "HigherBounds");
	for (o=0;o <= NBVERTICES;++o)
	{
		int x;

		fprintf(stream, "\tdd ");
		// then, the maximum bounds
		n = SUM;
		d = o;
		for (x = N;x>=0;--x)
		{
			Values[x]=n;
			n-=d;
			if (n<0) n = 0;
			//if (n>SUM) n = SUM;
			d+=2;
		}
		for (x = 0;x<=N;++x)
		{
			if (x)
			{
				fprintf(stream, ",");
			}
			fprintf(stream, "%d",Values[x]);
		}
		for (x=N+1;x<ALIGN;++x)
		{
			fprintf(stream, ",-1");
		}
		fprintf(stream, "\n");
	}
/*	fprintf(stream, "\tdd (%s-offset hsum), %d\n", OffsetMagic, Offset_hsum);
	fprintf(stream, "\tdd (%s-offset vsum), %d\n", OffsetMagic, Offset_vsum);
	fprintf(stream, "\tdd (%s-offset hcount), %d\n", OffsetMagic, Offset_hcount);
	fprintf(stream, "\tdd (%s-offset vcount), %d\n", OffsetMagic, Offset_vcount);
	fprintf(stream, "\tdd (%s-offset LowerBounds), %d\n", OffsetMagic, Offset_LowerBounds);
	fprintf(stream, "\tdd (%s-offset HigherBounds), %d\n", OffsetMagic, Offset_HigherBounds);*/
#if MASM
	fprintf(stream, "\tif (offset hsum-%s) NE %d\n", OffsetMagic, Offset_hsum);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");
	
	fprintf(stream, "\tif (offset vsum-%s) NE %d\n", OffsetMagic, Offset_vsum);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");

	fprintf(stream, "\tif (offset hcount-%s) NE %d\n", OffsetMagic, Offset_hcount);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");

	fprintf(stream, "\tif (offset vcount-%s) NE %d\n", OffsetMagic, Offset_vcount);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");

	fprintf(stream, "\tif (offset LowerBounds-%s) NE %d\n", OffsetMagic, Offset_LowerBounds);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");

	fprintf(stream, "\tif (offset HigherBounds-%s) NE %d\n", OffsetMagic, Offset_HigherBounds);
	fprintf(stream, "\terror\n");
	fprintf(stream, "\tendif\n");
#endif
#endif
#if PARTS
	fclose(stream);
	stream = NULL;
#endif
#if !PARTS
#if NASM
	fprintf(stream, "\tsection .code\n");
	fprintf(stream, "\textern _SaveSolution\n");
#endif
#if FASM
	fprintf(stream, "\tsection '.text' code readable executable\n");
	fprintf(stream, "\textrn _SaveSolution\n");
	fprintf(stream, "SECTION_START:\n");
	fprintf(stream, "macro align Alignment {\n");
	fprintf(stream, "\tREPEAT (Alignment-1)-(($-SECTION_START+Alignment-1) mod Alignment)\n");
	fprintf(stream, "\tret\n");
	fprintf(stream, "\tEND REPEAT\n");
	fprintf(stream, "}\n");
#endif
#if MASM
	fprintf(stream, "\t.code\n");
	fprintf(stream, "\textrn _SaveSolution:near\n");
#endif
#endif
	Enumerate();

	for(n=0;n<Routine;++n)
	{
		fprintf(stream2, "extern Compute%d();\n", n);
	}
#if !PARTS
#if MASM
	fprintf(stream, "\tend\n");
#endif
#endif
	
	fclose(stream2);
	fclose(stream);
	stream = NULL;
	return 0;
}
