//-------------------------------------
//
// SuperCode (c) 1996 by T.Kühn 
//
// Programmiersprache:	ANSI-C
// Projektstart:			12.7.95
//
// Modul:				Super-Code
//
//-------------------------------------
// max_equal * num_colors >=	num_columns
//-------------------------------------


#include <clib/alib_protos.h>
#include <pragma/graphics_lib.h>
#include <pragma/intuition_lib.h>
#include <stdlib.h>
#include <time.h>


#include <struct.h>




struct Field player1;

//-------------------------------------
ULONG random(ULONG n)
{
	ULONG r;

	r=(rand()-1)*(n+1)/RAND_MAX;

	return r;
}
//-------------------------------------


//-------------------------------------
struct GameEntry *code_getnexttry(struct GameEntry *old)
{
	struct GameEntry *entry=0;

	if (old)
	{
		entry=(struct GameEntry *)old->node.ln_Succ;
		if (!entry->node.ln_Succ) entry=0;
	}
	return entry;
}
//-------------------------------------
struct GameEntry *code_getprevtry(struct GameEntry *old)
{
	struct GameEntry *entry=0;

	if (old)
	{
		entry=(struct GameEntry *)old->node.ln_Pred;
		if (entry)
			if (entry->node.ln_Pred)
				if (entry->node.ln_Pred->ln_Pred)
				{
				}
				else
				{
					entry=0;
				}
	}
	return entry;
}
//-------------------------------------
struct GameEntry *code_get1sttry(struct Field *player)
{
	struct GameEntry *entry=(struct GameEntry *)player->try.lh_Head;

	entry=code_getnexttry(entry);

	return entry;
}
//-------------------------------------
struct GameEntry *code_getnumtry(struct Field *player,LONG n)
{
	struct GameEntry *entry=code_get1sttry(player);

	while (--n>0)
	{
		entry=code_getnexttry(entry);
	}

	return entry;
}
//-------------------------------------
struct GameEntry *code_getcombi(struct Field *player)
{
	struct GameEntry *entry=(struct GameEntry *)player->try.lh_Head;
	return entry;
}
//-------------------------------------
struct GameEntry *code_getlsttry(struct Field *player)
{
	struct GameEntry *entry=(struct GameEntry *)player->try.lh_TailPred;

	return entry;
}
//-------------------------------------



//-------------------------------------
ULONG code_getpoints(struct Field *player)
{
	ULONG x1=player->columns;
	ULONG x2=player->num_colors;
	LONG y=0;
	LONG f2,f1;

	f1=MIN(player->max_equal,x1);
	f2=1;

	switch (player->val_order)
	{
		case ORDER_POS:
			f1=1;
			f2=1;
			break;
		case ORDER_DESC:
			f2=3;
			break;
		case ORDER_RANDOM:
			f2=4;
			break;
	}

	y= (x1*x1 * x2*x2 * f1 * f2 - x1 * x2 * player->max_equal * (player->lines-1)) * 10;

	if (y<0) y=0;

	return y;
}
//-------------------------------------


//-------------------------------------
void code_fieldclear(struct Field *player)
{
	if (player)
	{
		List_Free(&player->try);
	}
}
//-------------------------------------
void code_freefield(struct Field *player)
{
	if (player)
	{
		code_fieldclear(player);
		player->columns=0;
	}
}
//-------------------------------------
struct GameEntry *code_newfield(struct Field *player)
{
	struct GameEntry *entry;
	LONG size=sizeof(struct GameEntry)+2*player->columns;

	entry=(struct GameEntry*)Memory_Alloc(size);
	entry->size=size;
	entry->field=((UBYTE*)entry)+sizeof(struct GameEntry);
	entry->value=((UBYTE*)entry)+sizeof(struct GameEntry)+player->columns;

	player->lines++;

	List_AddTail(&player->try,&entry->node);

	return entry;
}
//-------------------------------------


//-------------------------------------
void code_resetplayer(struct Field *player)
{
	player->columns=prg_prefs->game.num_columns;
	player->num_colors=prg_prefs->game.num_colors;
	player->max_equal=prg_prefs->game.max_equal;
	player->val_order=prg_prefs->game.val_order;
	player->lines=0;
	player->started=FALSE;

	while (player->max_equal * player->num_colors < player->columns)
	{
		player->num_colors++;
	}
}
//-------------------------------------
void code_initplayer(struct Field *player)
{
	if (player)
	{
		List_Init(&player->try,NT_TRY,0);

		code_resetplayer(player);
	}
}
//-------------------------------------


//-------------------------------------
void code_newcomb(struct Field *player)
{
	if (player)
	{
		code_fieldclear(player);
		code_resetplayer(player);
	}
	if (player)
	{
		UBYTE *equals=Memory_Alloc(player->num_colors+2);
		struct GameEntry *entry;
		ULONG t,w=player->columns;
		ULONG n=player->num_colors;
		UBYTE *field;

		entry=code_newfield(player);

		field=entry->field;

		srand( time(0) * VBeamPos() );
		for (t=0;t<w;t++)
		{
			field[t]=random(n-1)+1;

			while (equals[field[t]] >= player->max_equal)
			{
				field[t]=random(n-1)+1;
			}
			equals[field[t]]++;
		}
		player->finish=FALSE;
		player->giveup=FALSE;
		player->lines=0;

		Memory_Free(&equals);

		code_newfield(player);
		player->started=FALSE;
	}
}
//-------------------------------------


//-------------------------------------
void code_set(struct Field *player,ULONG pos,ULONG value)
{
	if (player)
	{
		struct GameEntry *entry=code_getlsttry(player);
		ULONG w=player->columns;
		ULONG n=player->num_colors;
		UBYTE *ent=entry->field;

		ent[pos]=value;

		if (!player->started)
		{
			ULONG dummy;
			CurrentTime(&player->sec_start,&dummy);
			player->started=TRUE;
			player->sec_start--;
		}
	}
}
//-------------------------------------
ULONG code_getfield(struct Field *player,struct GameEntry *entry,ULONG pos)
{
	ULONG back=0;

	if (player && entry)
	{
		UBYTE *ent=entry->field;
		ULONG w=player->columns;

		if (pos<w) back=ent[pos];
	}
	return back;
}
//-------------------------------------
ULONG code_getvalue(struct Field *player,struct GameEntry *entry,ULONG pos)
{
	ULONG back=0;

	if (player && entry)
	{
		UBYTE *ent=entry->value;
		ULONG w=player->columns;

		if (pos<w) back=ent[pos];
	}
	return back;
}
//-------------------------------------
void code_comparelast(struct Field *player)
{
	if (player)
	{
		struct GameEntry *combi=code_getcombi(player);
		struct GameEntry *entry=code_getlsttry(player);
		ULONG tot=0,set=0;
		ULONG w=player->columns;
		ULONG n=player->num_colors;
		ULONG s,t;
		UBYTE *val=entry->value;

		UBYTE *com=Memory_Alloc(2*w);
		UBYTE *ent=com+w;

		memcpy(com,combi->field,w);
		memcpy(ent,entry->field,w);

		for (t=0;t<w;t++)
		{
			if (ent[t]>0) set++;
		}

		if (set==w)
		{
			for (t=0;t<w;t++)
			{
				if (com[t]==ent[t])
				{
					tot++;
					val[t]=BLACK;			// schwarzes
					com[t]=0;
					ent[t]=0;
				}
			}
	
			for (t=0;t<w;t++)
			{
				if (ent[t]>0)
				{
					for (s=0;s<w;s++)
					{
						if (com[s]==ent[t])
						{
							val[t]=WHITE;	// weisses
							com[s]=0;
							ent[t]=0;
						}
					}
				}
			}
	
			if (tot==w)
			{
				ULONG dummy;
				player->finish=TRUE;
				CurrentTime(&player->sec_finish,&dummy);
			}
			else if (player->val_order==ORDER_DESC)
			{
				BOOL chg=TRUE;

				while(chg)
				{
					chg=FALSE;
					for(t=0;t<(w-1);t++)
					{
						if (val[t] < val[t+1])
						{
							chg=TRUE;
							s=val[t];
							val[t]=val[t+1];
							val[t+1]=s;
						}
					}
				}
			}
			else if (player->val_order==ORDER_RANDOM)
			{
				ULONG p1;
				ULONG p2;
				for(t=0;t<3*w;t++)
				{
					p1=random(w-1);
					p2=random(w-1);
					if (p1!=p2)
					{
						s=val[p1];
						val[p1]=val[p2];
						val[p2]=s;
					}
				}
			}

			if (!player->finish)
			{
				code_newfield(&player1);
			}
		}
		Memory_Free(&com);
	}
}
//-------------------------------------
void code_giveup(struct Field *player)
{
	struct GameEntry *combi=code_getcombi(player);
	ULONG w=player->columns,t;

	if (!player->finish)
	{
		player->finish=TRUE;
		player->giveup=TRUE;
	
		for (t=0;t<w;t++)
		{
			code_set(player,t,code_getfield(player,combi,t));
		}
	}
}
//-------------------------------------

/*
//-------------------------------------
void code_output(struct Field *player)
{
	struct GameEntry *entry=code_get1sttry(player);
	ULONG w=player->columns;
	ULONG n=0,t;

	printf("\14SUPER-CODE \n\n");

	while(entry)
	{
		printf("%2.2d : ",++n);
		for (t=0;t<w;t++)
		{
			printf("%2.2d ",code_getfield(player,entry,t));
		}
		printf("  ");

		for (t=0;t<w;t++)
		{
			switch (code_getvalue(player,entry,t))
			{
				case BLACK:	printf("S");break;
				case WHITE:	printf("w");break;
				default:		printf(".");break;
			}
		}
		printf("\n\n");
		entry=code_getnexttry(entry);
	}
}
//-------------------------------------
void code_test()
{
	ULONG t=1,s,v;
	struct Field *player=&player1;

	code_output(&player1);

	while(!player->finish)
	{
		code_newfield(player);

		printf("\n%d. Versuch\n",t);

		for (s=0;s<player->columns;s++)
		{
			scanf("%d",&v);
			if (v==0) return;
			code_set(player,s,v);
		}
		code_comparelast(player);
		code_output(player);
		t++;
	}

}
//-------------------------------------
*/

//-------------------------------------
void code_init()
{
	code_initplayer(&player1);

	code_newcomb(&player1);

//	code_test();
}
//-------------------------------------
void code_free()
{
	code_freefield(&player1);
}
//-------------------------------------

