/******************************************************************************
 * Copyright (C) International Computer Science Institute, 1995.  COPYRIGHT   *
 * NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject  *
 * to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in     *
 * the file "Doc/License" of the Sather distribution.  The license is also    *
 * available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.   *
 * -----> Please email comments to "sather-bugs@icsi.berkeley.edu". <-------- *
 *                                                                            *
 * heat.cc                                                                    *
 * implements heat distribution calculations                                  *
 * Version 1.0, June 1996, by Claudio Fleiner		                      *
 ******************************************************************************/
#include <stream.h>
#include <math.h>
#include "times.h"

class HEAT {
	float* t1,*t2;
    public:
	int rows,cols;
	HEAT() {
		cols=0;
		rows=0;
		t1=t2=0;
	}
	HEAT(int c,int r) {
		rows=r;
		cols=c;
		t1=new float[r*c];
		t2=new float[r*c];
	}

	float &operator()(int x,int y) {
		return t1[x+y*cols];
	}

	HEAT &operator=(HEAT r) {
		if(t1!=0) delete[] t1;
		if(t2!=0) delete[] t2;
		rows=r.rows;
		cols=r.cols;
		t1=new float[rows*cols];
		t2=new float[rows*cols];
		memcpy(t1,r.t1,sizeof(float)*rows*cols);
		memcpy(t2,r.t2,sizeof(float)*rows*cols);
	}

	print() {
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				float h=(*this)(j,i);
				if(h>15) h=15.0;
				cout <<  " .\'\":;-=!|+*#%$@"[(int)h];
			}
			cout << "\n";
		}
		cout<<"\n";
	}

	heat_step() {
		for(int x=0;x<cols;x++)
			for(int y=0;y<rows;y++) {
				int d=1;
				float h=(*this)(x,y);
				if(x>0) { d++;h+=(*this)(x-1,y); }
				if(y>0) { d++;h+=(*this)(x,y-1); }
				if(x<cols-1) { d++;h+=(*this)(x+1,y); }
				if(y<rows-1) { d++;h+=(*this)(x,y+1); }
				t2[x+y*cols]=h/(float)d;
			}
		float *t=t1;
		t1=t2;
		t2=t;
	}
};


extern "C" { int atoi(const char *); }

/* run some predefined patterns used to check if the code
   runs correctly */
void run_test()
{
	HEAT h(30,40);
	h(0,0)=1000.0;
	h(h.cols-1,0)=2000.0;
	h(0,h.rows-1)=3000.0;
	h(h.cols-1,h.rows-1)=4000.0;
	for(int i=0;i<100;i++) h.heat_step();
	for(int y=0;y<h.rows;y++) {
		for(int x=0;x<h.cols;x++) cout << form("%4d ",(int)((100.0*h(x,y))));
		cout << '\n';
	}
}

void usage() {
	cout << "USAGE: heat TEST\n"
	     << "       heat [-p] size steps\n";
}

int main(int argc,char *argv[]) {
	int print=0;
	int size=0;
	int steps=0;
	if(argc==2 && strcmp(argv[1],"TEST")==0) { run_test();exit(0); }
	if(argc==4 && strcmp(argv[1],"-p")==0) {
		print=1;
		size=atoi(argv[2]);
		steps=atoi(argv[3]);
	} else if(argc==3) {
		size=atoi(argv[1]);
		steps=atoi(argv[2]);
	} else {
		usage();
		return 1;
	}
	HEAT h(size,size);
	h(0,0)=size*50;
	h(size-1,0)=h(0,0);
	h(0,size-1)=h(0,0);
	h(size-1,size-1)=h(0,0);

	TIMES t;
	t.start();

	for(int i=0;i<steps;i++)  h.heat_step();

	TIMES e=t.elapsed();
	if(print) h.print();
	cout << e.str();
}
