Skills/C language

Hanoi Tower

섬그늘 2012. 5. 18. 17:44

What is Hanoi Tower?

see http://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94

 

When you faced "Do you want to read previous data file? (Y/N) " at the first time, press 'n'.

You can control the progress speed by pressing up and down arrow key.

 

Below is source code which does not use recursion routine.

--------------

//Hanoi Tower.c <-- ハノイの塔
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>

#define ESC 27
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define EXTENDASCII -32

void gotoxy(int, int);
void prtscr(int**);    // print current screen
void prtchar(int, int, int);
void prtspace(int, int);
void move(int, int**);
void delay();
void prttime(int);
int calnext(int, int**);

int start(int);
int goal(int);

int speed=50;
int y0=1, x0=3;     // char will be printed at (x, y) = (x[0]+x0, y+y0)
int x[]={3, 7, 11};
int xdis=4, ldis=17, ydis=20; //xdis : distance between poll, ldis : dist. btw section, ydis : total height of show
int num=12;      //number of discs
int sect=1;      //number of layer sections to show
int clay[3];     //current number of discs at each layer, next number of...

clock_t mysec[3];
/****************************************************/

main ()

{
 int i, j, **twr;  //twr : 2-dimension array for each numbers in towers
 long cnt=0;
 int mov;    //0~5 : 0>>1, 1>>0, 1>>2, 2>>1, 2>>0, 0>>2
 int f_read=0;
 char ch;
 char fname[20]="my_hanoi.txt";
 FILE *fp;

  printf("Do you want to read previous data file? (Y/N) ");
  ch=getch();
  if(ch=='Y' || ch=='y')
  {
   f_read=1;
   fp=fopen(fname, "r");   //save & exit
   fscanf(fp, "%d", &num);
  }
  else
  {
   printf("\nEnter number of initial layers (n<80) : ");
   scanf("%d", &num);
  }
  sect=1+(num-1)/ydis;
 
  twr=(int **)calloc(3,sizeof(int*));
  for (i=0; i<3; i++)  //tower0--start, tower1--temp, tower2--destination
  {
   twr[i]=(int *)calloc(num,sizeof(int));
  }

  if (f_read==1)  //read previous data from file
  {
   fscanf(fp, "%ld %d %d", &cnt, &mov, &mysec[0]);
   for (i=0; i<3; i++)
   {
    fscanf(fp, "%d", &clay[i]);
    for (j=0; j<clay[i]; j++)
     fscanf(fp, "%d", &twr[i][j]);
   }
   fclose(fp);
  }
  else
  {
   clay[0]=num;
   mov=(num%2)*5;   //num=odd --> 5; 0>>2, num=even --> 0; 0>>1
   for (j=0; j<num; j++)
    twr[0][j]=num-j;
  }
 prtscr(twr);
 mysec[1]=clock();

 //logic start!!!

 do
 {
  if(kbhit())
  {
   ch=getch();
   if(ch==ESC)
   {
    mysec[1]=clock()-mysec[1];  //eclipsed time at this trial
    mysec[2]=mysec[0]+mysec[1];  //accumulated eclipsed time so far
    gotoxy (20,y0+num+2);
     printf("Do you want to save data at file? (Y/N) ");
     ch=getch();
     if(ch=='Y' || ch=='y')
     {
      printf("\nThis trial         : ");prttime(mysec[1]);
      printf("\nTotal accumulation : ");prttime(mysec[2]);printf("\n");

      fp=fopen(fname, "w");   //save & exit
      fprintf(fp, "%d\n %ld\n %d\n %d\n", num, cnt, mov, mysec[2]);
      for (i=0; i<3; i++)
      {
       fprintf(fp, "%d\n", clay[i]);
       for (j=0; j<clay[i]; j++)
        fprintf(fp, "%d\n", twr[i][j]);
      }
      fclose(fp);
      ch=getch();
      exit(0);
     }
     else exit(0);
   }
  
   else //if(ch==EXTENDASCII)
   {
    switch(ch)
    {
    case UP:
     speed=(speed+10<1000) ? speed+10 : speed;
     break;
    case DOWN:
     speed=(speed-10>9) ? speed-10 : speed;
     break;
    }
   }
  }
  gotoxy (1,y0+num+2);
  printf("count=%d ", cnt);
  delay();
  move(mov, twr);
//  prtscr(twr);
  cnt++;
  mov=calnext(mov,twr); 
 }while(clay[2]<num);

 gotoxy (1,y0+num+2);
 printf("count=%d\n\n", cnt);

 free (twr);
 scanf("%c", &ch);
 getchar();

return;
}
int calnext(int a, int **twr)
{
 int i, j, k, st, ds, ans;
 int nxt[2][3];
 int ncnt=0;
 for (k=0; k<6; k++)
 {
  if ((k^a)!=1)    //should not be (0,1), (2,3), (4,5)
  {
   i=start(k);
   j=goal(k);
   if(clay[i]!=0)   //start layer <>0
   {
    if(clay[j]==0)
    {
     if((clay[i]==1 && twr[i][0]>1) || clay[i]!=1) //should not be (0,1)>>(1,0)
     {
      nxt[ncnt][0]=k;
      nxt[ncnt][1]=clay[j];
      nxt[ncnt][2]=twr[i][clay[i]-1];
      ncnt++;
     }
    }
    else
    {
     st=twr[i][clay[i]-1]; // top number of start tower
     ds=twr[j][clay[j]-1]; // top number of goal tower
     if((st<ds) && (st%2 != ds%2))
     {
      nxt[ncnt][0]=k;
      nxt[ncnt][1]=clay[j];
      nxt[ncnt][2]=twr[i][clay[i]-1];
      ncnt++;
     }
    }
   }
  }
 }
 if (ncnt==0)
 {
  gotoxy (1,y0+num+1);
  printf("mov= %d ",a);
  for(i=0; i<3; i++)
  {
   printf("error!!!!!!!! clay[%d]= %d\n",i,clay[i]);
  }
  exit(0);
 }
 if (ncnt>1)
 {
  if (nxt[0][1]==nxt[1][1])
   ans=(nxt[0][2]>nxt[1][2]) ? nxt[0][0]:nxt[1][0];
  else
   ans=(nxt[0][1]>nxt[1][1]) ? nxt[0][0]:nxt[1][0];
 }
 else
  ans=nxt[0][0];
 gotoxy (1,y0+num+3);
 printf("ncnt= %d speed= %d",ncnt, speed);
  
 return(ans);
}
void move(int a, int **twr)
{
 int i, j;
 i=start(a);
 j=goal(a);
 twr[j][clay[j]]=twr[i][clay[i]-1];
 prtspace(clay[i]-1,i);
 prtchar(clay[j],j,twr[j][clay[j]]);
 clay[j]++;
 clay[i]--;
}
int start(int a)

 int stt = ((a/2)+(a%2))%3; //a=0~5, org=0,1,1,2,2,0
 return(stt);
}
int goal(int a)
{
 int dst = ((a+2)/2-a%2)%3; //a=0~5, dst=1,0,2,1,0,2
 return(dst);
}

void prtscr(int **twr)
{
 int i, j;
 system("cls");
 for(j=0; j<3; j++)
 {
  for(i=0; i<clay[j]; i++)
  {
   if(twr[j][i]!=0)
   {
    prtchar(i,j,twr[j][i]);
   }
  }
 }
}

void prtchar(int i, int j, int val)
{
 int k=i/ydis;
 gotoxy(x[j]+k*ldis,y0+(num-(i-k*ydis)));
 printf("%d",val);
}

void prtspace(int i, int j)
{
 int k=i/ydis;
 gotoxy(x[j]+k*ldis,y0+(num-(i-k*ydis)));
 printf("  ");
}

void gotoxy(int x, int y)
{
COORD Cur;
Cur.X=x;
Cur.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Cur);
}
void delay()
{
 int i,j;
 for(i=0; i<1000000/speed; i++)
  for(j=0; j<i; j++)
   ;
}

void prttime(int t)
{
 int d, h, m, s;
 s=t/1000;
 d=s/3600/24;
 s=s-d*3600*24;
 h=s/3600;
 s=s-h*3600;
 m=s/60;
 s=s%60;
 printf("%d days %02d:%02d:%02d",d,h,m,s);
}
//end of source