#include "stdio.h"

int count; // количество состояний
FILE * f;  // указатель на файл

// структура, хранящая состояния

typedef struct state
{
  int cf, cg, h, fa, fb, ga, gb;
} state;

state state_list[100]; // список полученных ранее состояний
int state_point;       // указатель на ожидающий заполнения элемент массива
state * st;            // указатель на временный объект состояния

// проверяет эквивалентность двух состояний

int eq_st (state * st1, state * st2)
{
  return ((st1->cf == st2->cf) && (st1->cg == st2->cg) && (st1->h == st2->h) && (st1->fa == st2->fa) 
	  && (st1->fb == st2->fb) && (st1->ga == st2->ga) && (st1->gb = st2->gb));
}

// проверяет, встречалось ли данное состояние ранее

int st_exist (state * st)
{
  int i;

  for (i = 0; i < state_point; i++)
    {
      if (eq_st (st, &state_list[i])) 
	return 1;
    }

  return 0;
}

// помезает новое состояние в массив

void put_st (state * st)
{
  state_list[state_point].cf = st->cf;
  state_list[state_point].cg = st->cg;
  state_list[state_point].h = st->h;
  state_list[state_point].fa = st->fa;
  state_list[state_point].fb = st->fb;
  state_list[state_point].ga = st->ga;
  state_list[state_point].gb = st->gb;

  state_point++;
}

// основная функция программы, осуществляющая рекурсивный просмотр всех достижимых состояний

void
func (int cf, int cg, int h, int fa, int fb, int ga, int gb, int fx, int fy, int gx, int gy)
{
  int t;         // переменная для временного хранения значений
  char chy, chh; // индикаторы изменения значений перемнных y и h

  // начальная инициализация

  chy = 0;
  chh = 0;

  st -> cf = cf;
  st -> cg = cg;
  st -> h = h;
  st -> fa = fa;
  st -> fb = fb;
  st -> ga = ga;
  st -> gb = gb;

  // если состояние не встречалось, то вывести значения и занести в список

  if (!st_exist (st))
    {
      count++;
      put_st (st);

      fprintf (f, "%d, %d", cf, cg);

      if ((cf < 3) && (cg < 3)) fprintf (f, ", #"); else fprintf (f, ", %d", h);
      fprintf (f, ", %d, %d, %d, %d\n", fa, fb, ga, gb);
    }

  // если возможно, переход на 1 команду вперед в функции f, 
  // затем рекурсивный вызов func с обновленными значениями и возврат исходных значений при возврате

  if (cf < 9)
    {
      switch (cf)
        {
        case 0:
          {
            cf++;
            fx = 4;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cf--;

            break;
          }
        case 1:
          {
            cf++;
            fy = 1;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cf--;

            break;
          }
        case 2:
          {
            cf++;
            h = fb;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cf--;

            break;
          }
        case 3:
          {
            cf++;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cf--;

            break;
          }
        case 4:
          {
            cf = 6;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cf = 4;

            break;
          }
        case 6:
          {
            if (h < fy) cf = 7;
            else
              {
                cf = 10;
                t = fy;
                fy = 3;
                chy = 1;
              }
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);

            if (chy)
              {
                fy = t;
                chy = 0;
              }

            cf = 6;

            break;
          }
        case 7:
          {
            if (h > fa)
              {
                cf = 8;
                t = fy;
                fy = 3;
                chy = 1;
              }
            else
              {
                cf = 9;
                t = h;
                h = fy;
                chh = 0;
              }

            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);

            if (chy)
              {
                fy = t;
                chy = 0;
              }

            if (chh)
              {
                h = t;
                chh = 0;
              }

            cf = 7;

            break;
          }
        case 8:
          {
            cf++;
            t = h;
            h = fy;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            h = t;
            cf--;

            break;
          }
        case 9:
          {
            cf++;
            t = fy;
            fy = 3;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            fy = t;
            cf--;
          }
        };
    }

  // если возможно, переход на 1 команду вперед в функции g, 
  // затем рекурсивный вызов func с обновленными значениями и возврат исходных значений при возврате

  if (cg < 12)
    {
      switch (cg)
        {
        case 0:
          {
            cg++;
            gx = 3;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg--;

            break;
          }
        case 1:
          {
            cg++;
            fy = 0;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg--;

            break;
          }
        case 2:
          {
            cg++;
            h = gb;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg--;

            break;
          }
        case 3:
          {
            cg++;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg--;

            break;
          }
        case 4:
          {
            cg = 9;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg = 4;

            break;
          }
        case 9:
          {
            cg = 11;
            t = gy;
            gy = 10;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg = 9;
            gy = t;

            break;
          }
        case 11:
	  {
            cg = 12;
            func (cf, cg, h, fa, fb, ga, gb, fx, fy, gx, gy);
            cg = 11;

            break;
          }
        };
    }
}

int
main (int argc, char * argv[])
{
  char file, cnt, filename[80]; // индикаторы параметров -file и -count, имя файла
  char pfile[] = "-file";       // параметр -file
  char pcount[] = "-count";     // параметр -count
  int i;

  // инициализация

  count = 0;
  file = 0;
  cnt = 0;
  state_point = 0;

  if (argc == 1)
    {
      // если нет параметров

      fprintf (stdout, "This program writes all reachable states of program in Task1\n");
      fprintf (stdout, "Krasnov Denis, 2010\n");
      fprintf (stdout, "Parameters:\n");
      fprintf (stdout, "-file <file_name> - write states to to the file <file_name>\n");
      fprintf (stdout, "-count - writes the number of states to the standard output\n");
    }
  else
    {
      // если есть параметры

      for (i = 1; i < argc; i++)
        {
          if (!strcmp (argv[i], pfile))
            {
	      // если есть параметр -file

              file = 1;
              i++;
              f = fopen (argv[i], "w");
            }

	  // если есть параметр -count

          if (!strcmp (argv[i], pcount))
            cnt = 1;
        }

      // если нет -file, открыть states.txt

      if (!file)
	f = fopen ("states.txt", "w");

      // основная часть программы: вывод состояний

      fprintf (f, "c_f, c_g, h, f.a, f.b, g.a, g.b\n");

      st = (state *) malloc (sizeof (state));

      func (0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0);

      free (st);

      // если естьпараметр -count, вывести количество состояний

      if (cnt) fprintf (stdout, "%d\n", count);

      fclose (f);
    }

  return 0;
}
