#include <v_lib.h>

/*
 * M = a * M1 + b * M2 + M3 * M4, where
 * a, b - constants,
 * M1, M2, M3, M4 - 3x3 matrices
 */
u32_t num_tasks;
s32_t min, max, delta;

vhandle_t rg;

vec_t next_random(void)
{
	s32_t x = urnNextLong(rg,delta+1);
	x += min;
	if(x)
		return x;
	else
	{
		return next_random();
	}
}

vec_t a, b;
matrix3_t M, M1, M2, M3, M4;

void create_args(void)
{
	int i,j;
	a = next_random();
	b = next_random();
	for(i=0;i<3;i++)
		for(j=0;j<3;j++)
		{
			M1[i][j] = next_random();
			M2[i][j] = next_random();
			M3[i][j] = next_random();
			M4[i][j] = next_random();
		}
}

void render_args()
{
	u32_t i;
	vboolean cleared = false;
	static char tmpbuf[1024];
	printf("       / %2d %2d %2d \\          / %2d %2d %2d \\   / %2d %2d %2d \\   / %2d %2d %2d \\ \n",
		(int)M1[0][0],(int)M1[0][1],(int)M1[0][2],
		(int)M2[0][0],(int)M2[0][1],(int)M2[0][2],
		(int)M3[0][0],(int)M3[0][1],(int)M3[0][2],
		(int)M4[0][0],(int)M4[0][1],(int)M4[0][2]);
	sprintf(tmpbuf,"(%2d) * | %2d %2d %2d | + (%2d) * | %2d %2d %2d | + | %2d %2d %2d | * | %2d %2d %2d |",
		(int)a,
		(int)M1[1][0],(int)M1[1][1],(int)M1[1][2],
		(int)b,
		(int)M2[1][0],(int)M2[1][1],(int)M2[1][2],
		(int)M3[1][0],(int)M3[1][1],(int)M3[1][2],
		(int)M4[1][0],(int)M4[1][1],(int)M4[1][2]);
	for(i=0;i<1022;i++)
	{
		if(tmpbuf[i] == '(')
		{
			if(tmpbuf[i+1] == ' ')
			{
				tmpbuf[i] = ' ';
				cleared = true;
			}
			else
				cleared = false;
		}
		else if(tmpbuf[i] == ')' && cleared)
		{
			tmpbuf[i] = ' ';
			cleared = false;
		}
	}
	puts(tmpbuf);		
	printf("       \\ %2d %2d %2d /          \\ %2d %2d %2d /   \\ %2d %2d %2d /   \\ %2d %2d %2d / \n",
		(int)M1[2][0],(int)M1[2][1],(int)M1[2][2],
		(int)M2[2][0],(int)M2[2][1],(int)M2[2][2],
		(int)M3[2][0],(int)M3[2][1],(int)M3[2][2],
		(int)M4[2][0],(int)M4[2][1],(int)M4[2][2]);
}

void render_res()
{
	printf("/ %4d %4d %4d \\\n",
		(int)M[0][0],(int)M[0][1],(int)M[0][2]);
	printf("| %4d %4d %4d |\n",
		(int)M[1][0],(int)M[1][1],(int)M[1][2]);
	printf("\\ %4d %4d %4d /\n",
		(int)M[2][0],(int)M[2][1],(int)M[2][2]);
}

void scale_m3(matrix3_t dest,matrix3_t src,vec_t scale)
{
	int i,j;
	for(i=0;i<3;i++)
		for(j=0;j<3;j++)
			dest[i][j] = src[i][j] * scale;
}

void add_m3(matrix3_t dest,matrix3_t src1,matrix3_t src2)
{
	int i,j;
	for(i=0;i<3;i++)
		for(j=0;j<3;j++)
			dest[i][j] = src1[i][j] + src2[i][j];
}

void eval_res(void)
{
	matrix3_t temp;
	scale_m3(M,M1,a);
	scale_m3(temp,M2,b);
	add_m3(M,M,temp);
	mat3MatMul(temp,M3,M4);
	add_m3(M,M,temp);
}

int main(int argc,char *argv[])
{
	u32_t i;
	u32_t seed;
	if(argc < 5)
	{
		puts("usage: 03-tst <seed> <num_tasks> <min> <max> [-answers]");
		return -1;
	}
	seed = atoi(argv[1]);
	num_tasks = atoi(argv[2]);
	min = atoi(argv[3]);
	max = atoi(argv[4]);
	delta = max - min;
	assert(delta > 0);
	rg = urnCreateGenerator(seed);
	if(argc > 5 && !strcmp(argv[5],"-answers"))
	{
		printf("Ответы:\n\n");
		for(i=0;i<num_tasks;i++)
		{
			printf("Вариант %d:\n",i+1);
			create_args();
			eval_res();
			render_res();
		}
	}
	else
	{
		printf("Задания:\n\n");
		for(i=0;i<num_tasks;i++)
		{
			printf("Вариант %d:\n",i+1);
			create_args();
			render_args();
		}
	}
	urnDestroyGenerator(rg);
	return 0;
}
