// КОНЮХ (С)  А.А.Дуванов АЗЫ ИНФОРМАТИКИ RU 2001

// Глобальные переменные программы
// -------------------------------
var numHorsesRU   = 6;      // Число коней (по умолчанию -- 6)
var dragAndDropRU = 0;      // Режим перетаскивания

var horsesRU = new Array();     // Массив коней
var listRU   = new programRU(); // Протокол
var lenProgScreen  = 10;        // Число строк программы на экране

// Игровое поле
var fieldLeftRU  = 60;  // координаты коня в первой (верхней) клетке
var fieldTopRU   = 144;
var fieldDLeftRU = 76;  // размеры клетки
var fieldDTopRU  = 76;
var fieldWidthRU = 258; // Ширина поля

var BadData  = "Не понимаю"; // команда не входит в СКИ Плюсика
var CantDo   = "Не могу";    // команду выполнить невозможно

// Рабочие переменные
var left1RU;                 //  Начальные и конечные координаты
var top1RU;                  //  перемещаемого коня
var left2RU;                 //  (left1RU,top1RU) --> (left2RU,top2RU)
var top2RU;                  //
var iHorseRU;                //  Индекс перемещаемого коня
var timerRU;                 //  Таймер
var dtRU=10;                 //  Временная задержка
var moveLeftRU;              //  Координаты
var moveTopRU;               //    перемещения
var dmoveLeftRU;             //  Приращения
var dmoveTopRU;              //    смещения

// Объект Конь
// -----------
function horseRU(color, left, top,id, visibility)
{
  this.color      = color;       // Цвет коня
  this.left       = left;        // Координата по x
  this.top        = top;         // Координата по y
  this.id         = id;          // Идентификатор коня
}


// Начальные установки программы
//
function iniRU()
{
  horsesRU[0] = new horseRU("black", 0, 0, "horse00");
  horsesRU[1] = new horseRU("black", 1, 0, "horse10");
  horsesRU[2] = new horseRU("black", 2, 0, "horse20");
  horsesRU[3] = new horseRU("white", 0, 2, "horse02");
  horsesRU[4] = new horseRU("white", 1, 2, "horse12");
  horsesRU[5] = new horseRU("white", 2, 2, "horse22");
  startRU();
}


// Пересчет координат коня в экранные координаты
function horseLeft(i) { return fieldLeftRU+i*fieldDLeftRU; }
function horseTop(i)  { return fieldTopRU+i*fieldDTopRU; }

// Перевод пользовательских координат коня в экранные
function userToScreen(x)
{
  var t;
  t = "321".indexOf(x);
  if (t != -1) return t;
  t = "abc".indexOf(x);
  return t;
}

// Перевод экранных координат коня в пользовательские
function screenToUser(b0,b1,e0,e1)
{
   return "abc".charAt(b0)+
          "321".charAt(b1)+
          "-"+
          "abc".charAt(e0)+
          "321".charAt(e1);
}

// Обработчики кнопок программной панели
// -------------------------------------

// Настройка программы
function optionRU()
{
  var str = setOptionRU();
  if (str)
  {
    if (numHorsesRU != parseInt(str.charAt(0)) ||
        dragAndDropRU != parseInt(str.charAt(1)))
    {
      numHorsesRU = parseInt(str.charAt(0));
      dragAndDropRU = parseInt(str.charAt(1));
      startRU();
    }
  }
}


// Постановка задачи
function aboutRU()
{
  window.showModalDialog("horsets.htm", "",
   "dialogWidth:400px;dialogHeight:340px;cеnter:yes;help:no;status:no");
}

// Пользовательские инструкции
function helpRU()
{
  window.showModalDialog("horsehl.htm", "",
   "dialogWidth:400px;dialogHeight:380px;cеnter:yes;help:no;status:no");

}


// Обработчики кнопок панели управления исполнителем
// =================================================

// Щелчок по аварийной надписи
// ---------------------------
function clickMesserRU()
{
  document.all['messer'].style.visibility="hidden";
  document.all['messfield'].style.visibility="hidden";
  document.all['baddata'].style.visibility="hidden";
  document.all['cantdo'].style.visibility="hidden";
}


// Ввод команды
// ------------
function enterRU(com)
{
  if (com.value != "")
  {
    // Проверим на "Не понимаю"
    if (isBadDataRU(com.value.toLowerCase()))
      {
        document.all['messer'].style.visibility="visible";
        document.all['messfield'].style.visibility="visible";
        document.all['baddata'].style.visibility="visible";
        document.all['cantdo'].style.visibility="hidden";
      }
    // Проверим на "Не могу"
    else if (isCantDoRU())
      {
        document.all['messer'].style.visibility="visible";
        document.all['messfield'].style.visibility="visible";
        document.all['baddata'].style.visibility="hidden";
        document.all['cantdo'].style.visibility="visible";
      }
    else
    {
      // Добавим команду в протокол
      listRU.Add(com.value);
      // Отрисовка программы
      drawListRU();
      // Выполним команду
      document.all['messer'].style.visibility="hidden";
      document.all['baddata'].style.visibility="hidden";
      document.all['cantdo'].style.visibility="hidden";
      document.all['messfield'].style.visibility="hidden";
      execRU();
      // Очистим поле команды
      com.value="";
    }
  }
}

// Проверка на окончание игры
function gameOverRU()
{
  var ret = true;

  // Черные кони внизу, а белые наверху
  if (horsesRU[0].top != 2) ret = false;
  if (horsesRU[1].top != 2 && numHorsesRU == 6) ret = false;
  if (horsesRU[2].top != 2) ret = false;
  if (horsesRU[3].top != 0) ret = false;
  if (horsesRU[4].top != 0 && numHorsesRU == 6) ret = false;
  if (horsesRU[5].top != 0) ret = false;

  // Если задача про 4 коней, то клетки (1,0) и (1,2) должны быть пусты

  if (numHorsesRU==4)
    for(var i=0; i<6; i++)
      if (i != 1 && i != 4)
        if (horsesRU[i].left == 1 && horsesRU[i].top == 0 ||
            horsesRU[i].left == 1 && horsesRU[i].top == 2)
              { ret= false; break; }

  if (ret) alert("Задача решена!");
}


// Отрисовка программы
// -------------------
function drawListRU()
{
 var str="";
 for(var i=0; i<listRU.len; i++)
   str += eval(i+1)+". "+listRU.program[i]+"\r\n";
 document.forma.list.value=str;
 document.forma.list.scrollTop=listRU.len>lenProgScreen ?
 (listRU.len-lenProgScreen)*document.forma.list.scrollHeight/lenProgScreen:0;
}


// Откатка
// -------
function undoRU()
{
  if(listRU.Undo())
  {
    // Отрисовать программное поле
    drawListRU();
    // Кони в начальное положение
    horsesIniRU();
    // Выполнить заново все команды до this.len
    for(var i=0; i<listRU.len; i++)
       ExecuteFast(listRU.Element(i));
    // Показать коней
    drawHorsesRU();
  }
}

// Накатка
// -------
function redoRU()
{
  if(listRU.Redo())
  {
    drawListRU();
    // Выполнить команду
    ExecuteFast(listRU.Element(listRU.len-1));
    // Показать коней
    drawHorsesRU();
  }
}
// =================================================

// Выполнение команды без мультипликации

function ExecuteFast(str)
{
  // Вычислим координаты перемещения коня
  leftTopMoveRU(str);

  // Определим индекс коня
  for(var i=0; i<6; i++)
   if (horsesRU[i].left == left1RU &&
       horsesRU[i].top  == top1RU &&
       document.all[horsesRU[i].id].style.visibility == "visible") break;

  iHorseRU = i;

  // Сделаем отметку о новых координатах
  horsesRU[iHorseRU].left = left2RU;
  horsesRU[iHorseRU].top = top2RU;
}

// Выполнение команды
// ------------------
// Перемещение коня iHorseRU (left1RU, top1RU) --> (left2RU, top2RU)
function execRU()
{

  // Поместим коня в верхний слой
  document.all[horsesRU[iHorseRU].id].style.zIndex = 1;


  // Двигаем коня
  dmoveLeftRU = left2RU > left1RU ? 20:-20;
  dmoveTopRU  = top2RU  > top1RU  ? 20:-20;
  moveLeftRU  = horseLeft(left1RU);
  moveTopRU   = horseTop(top1RU);
  timerRU = setInterval("moveRU()", dtRU);

}

// Движение коня
// -------------
function moveRU()
{
  var ml=true;
  var mt=true;
  if (Math.abs(horseLeft(left2RU)-moveLeftRU) > Math.abs(dmoveLeftRU))
    moveLeftRU += dmoveLeftRU;
  else ml=false;
  if (Math.abs(horseTop(top2RU)-moveTopRU) > Math.abs(dmoveTopRU))
    moveTopRU += dmoveTopRU;
  else mt=false;
  var obj = document.all[horsesRU[iHorseRU].id].style;
  if (ml) obj.posLeft = moveLeftRU;
  if (mt) obj.posTop = moveTopRU;


  if ( !ml && !mt)
  {
    // Сбросим таймер
    clearInterval(timerRU);
    // Подровняем коня на новом месте
    obj.posLeft = horseLeft(left2RU);
    obj.posTop  = horseTop(top2RU);
    // Поместим коня в нулевой слой
    obj.zIndex=0;
    // Сделаем отметку о новых координатах
    horsesRU[iHorseRU].left = left2RU;
    horsesRU[iHorseRU].top = top2RU;
    // Если решение окончено, выдадим сообщение
    gameOverRU();
  }
}


// Проверка на "Не понимаю"
// ------------------------
function isBadDataRU(str)
{
  // Проверка синтаксиса команды
  if ("abc".indexOf(str.charAt(0)) == -1  ||
      "123".indexOf(str.charAt(1)) == -1  ||
      str.charAt(2) != "-"                ||
      "abc".indexOf(str.charAt(3)) == -1  ||
      "123".indexOf(str.charAt(4)) == -1) return true;

  // Вычислим координаты перемещения коня
  leftTopMoveRU(str);

  // Проверка хода на букву "Г"
  if ( Math.abs(left1RU-left2RU)==2 &&  Math.abs(top1RU-top2RU)==1  ||
       Math.abs(left1RU-left2RU)==1 &&  Math.abs(top1RU-top2RU)==2) return false;
  else                                                              return true;
}

// Вычисление координат перемещения коня
// -------------------------------------
function leftTopMoveRU(str)
{
  // Вычислим координаты перемещения коня
  left1RU = userToScreen(str.charAt(0));
  top1RU  = userToScreen(str.charAt(1));
  left2RU = userToScreen(str.charAt(3));
  top2RU  = userToScreen(str.charAt(4));
}


// Проверка на "Не могу"
// ------------------------
function isCantDoRU()
{
  var i;
  // Есть ли конь на исходном месте

  for(i=0; i<6; i++)
   if (horsesRU[i].left == left1RU &&
       horsesRU[i].top  == top1RU &&
       document.all[horsesRU[i].id].style.visibility == "visible") break;

  if (i<6)
  {
    // Запомним индекс перемещаемого коня
    iHorseRU = i;
    // Свободно ли конечное место
    for(i=0; i<6; i++)
     if (horsesRU[i].left == left2RU &&
         horsesRU[i].top  == top2RU &&
         document.all[horsesRU[i].id].style.visibility == "visible") break;

    if (i<6) return true;
    else     return false;
  }
  else return true;
}


// Сброс среды в начальное положение
// ---------------------------------
function startRU()
{
  document.forma.list.value = document.forma.com.value = "";
      document.all['messer'].style.visibility="hidden";
      document.all['baddata'].style.visibility="hidden";
      document.all['cantdo'].style.visibility="hidden";
      document.all['messfield'].style.visibility="hidden";
  listRU.Cls();
  horsesIniRU();
  drawHorsesRU();
}

// Откатка в самое начало
// ---------------------------------
function undoDownRU()
{
  listRU.UndoDown();
  document.forma.list.value = document.forma.com.value = "";
      document.all['messer'].style.visibility="hidden";
      document.all['baddata'].style.visibility="hidden";
      document.all['cantdo'].style.visibility="hidden";
      document.all['messfield'].style.visibility="hidden";
  horsesIniRU();
  drawHorsesRU();
}

// Начальные координаты коней
// --------------------------
function horsesIniRU()
{
  horsesRU[0].left = horsesRU[0].top = 0;
  horsesRU[1].left = 1
  horsesRU[1].top  = 0;
  horsesRU[2].left = 2
  horsesRU[2].top  = 0;
  horsesRU[3].left = 0
  horsesRU[3].top  = 2;
  horsesRU[4].left = 1
  horsesRU[4].top  = 2;
  horsesRU[5].left = horsesRU[5].top = 2;
}


// Отрисовка игрового поля
// -----------------------
function drawHorsesRU()
{
  for (var i = 0; i < 6; i++)
  {
    document.all[horsesRU[i].id].style.pixelLeft = horseLeft(horsesRU[i].left);
    document.all[horsesRU[i].id ].style.pixelTop = horseTop(horsesRU[i].top);

    var temp = "visible";
    if ((i == 1 || i == 4) && numHorsesRU == 4) temp = "hidden";
    document.all[horsesRU[i].id].style.visibility = temp;
  }
}

//====== Начало описания объекта ProgramRU ======
// Конструктор
function programRU()
{
 // Свойства
 this.program = new Array(); // Массив строк протокола
 this.len     = 0;           // Длина протокола
 this.maxlen  = 0;           // МаксимальнаЯ длина протокола

 // Методы
 this.Add   = _Add;          // Добавить строку
 this.Undo  = _Undo;         // Откатка
 this.UndoDown = _UndoDown;  // Откатка в самое начало
 this.Redo  = _Redo;         // Накатка
 this.Cls   = __Cls;         // Сброс протокола
 this.Element = __Element;   // i-ая строка протокола
}

//--- Описание методов объекта

// Добавить строку
function _Add(str)
{
 this.program[this.len++] = str;
 this.maxlen = this.len;
}

// Откатка
function _Undo()
{
 var ret = false;
 if (this.len) {this.len--; ret = true;}
 return ret;
}

// Откатка в самое начало
function _UndoDown()
{
  this.len = 0;
}

// Накатка
function _Redo()
{
 var ret = false;
 if (this.len < this.maxlen) {this.len++; ret = true;}
 return ret;
}

// Сброс протокола
function __Cls()
{
  this.len = this.maxlen = 0;
}

// ВозвращаетсЯ i-строка протокола
// Если строки нет, возвращаетсЯ null
function __Element(i)
{
  var ret = null;
  if(i>=0  && i<=this.len-1) ret = this.program[i];
  return ret;
}
//==== Конец описания объекта ProgramRU ====

//======= Перетаскивание ======

// Назначение своих обработчиков для событий, связанных с перетаскиванием
document.onmousedown=mouseDownEvent;
document.onmousemove=mouseMoveEvent;
document.onmouseup=mouseUpEvent;

var imgDragging = null; // Указатель на перетаскиваемый элемент

// Перевод идентификатора коня в его индекс в массиве horsesRU
function idToIndexRU(id)
{
  if (id.charAt(6)==0) return id.charAt(5);
  else return parseInt(id.charAt(5))+3;
}


// Обработка захвата элемента
// --------------------------
function mouseDownEvent()
{
  var strID = event.srcElement.id;
  if (strID.indexOf("horse") != -1 && dragAndDropRU)   // Это конь?
  {
    imgDragging = event.srcElement;      // Запомним ссылку на коня
    iHorseRU = idToIndexRU(strID);       // Запомним индекс коня
    left1RU = horsesRU[iHorseRU].left;   // Начальные координаты
    top1RU  = horsesRU[iHorseRU].top;    // перемещаемого коня

    dxHorseRU  = event.offsetX;
    dyHorseRU  = event.offsetY;

    // Коня в верхний слой
    imgDragging.style.zIndex = 1;
  }
  else imgDragging = null; // Перетаскивание запрещено
}

// Обработка перемещения элемента
// ------------------------------
function mouseMoveEvent()
{
  if (imgDragging != null)
  {
    // Коня -- в положение мышиного курсора
    // если он не выходит за пределы поля

    var left  = event.x - dxHorseRU;


    if (left >fieldLeftRU+fieldDLeftRU*2) left = fieldLeftRU+fieldDLeftRU*2
    else if (left < fieldLeftRU) left = fieldLeftRU;

    var top  = event.y - dyHorseRU;
    if (top > fieldTopRU+fieldDTopRU*2) top = fieldTopRU+fieldDTopRU*2
    else if (top < fieldTopRU) top = fieldTopRU;

    imgDragging.style.pixelLeft = left;
    imgDragging.style.pixelTop = top;
  }

  // Остановим прохождение события
  event.cancelBubble = true;
  event.returnValue = false;
}

// Обработка освобождения элемента
// -------------------------------
function mouseUpEvent()
{
  if (imgDragging != null)
  {
    // В какую клетку поля попали

    var posLeft = Math.round((imgDragging.style.pixelLeft
                  - fieldLeftRU) /fieldDLeftRU);
    var posTop  = Math.round((imgDragging.style.pixelTop
                  - fieldTopRU) /fieldDTopRU);

    // Проверим правильность хода

    var str = screenToUser(horsesRU[iHorseRU].left,
                           horsesRU[iHorseRU].top,
                           posLeft,posTop);
    var ret = true;

    if (isBadDataRU(str))
    {
      // Не понял
      document.all['messer'].style.visibility="visible";
      document.all['baddata'].style.visibility="visible";
      document.all['cantdo'].style.visibility="hidden";
      document.all['messfield'].style.visibility="visible";
      ret = false;
    }
    else if(isCantDoRU())
    {
      // Не могу
      document.all['messer'].style.visibility="visible";
      document.all['baddata'].style.visibility="hidden";
      document.all['cantdo'].style.visibility="visible";
      document.all['messfield'].style.visibility="visible";
      ret = false;
    }

    if(ret)
    {
      // Присвоим коню новые координаты
      horsesRU[iHorseRU].left = posLeft;
      horsesRU[iHorseRU].top  = posTop;

      // Подровняем коня в клетке
      imgDragging.style.pixelLeft = horseLeft(horsesRU[iHorseRU].left);
      imgDragging.style.pixelTop  = horseTop(horsesRU[iHorseRU].top);

     // Спрячем сообщения
      document.all['messer'].style.visibility="hidden";
      document.all['baddata'].style.visibility="hidden";
      document.all['cantdo'].style.visibility="hidden";
      document.all['messfield'].style.visibility="hidden";

      // Добавим команду в протокол
      listRU.Add(str);

      // Отрисовка программы
      drawListRU();

      // Проверка на окончание
      gameOverRU();
    }
    else
    {
      // Вернем коня в прежнее положение
      imgDragging.style.pixelLeft = horseLeft(horsesRU[iHorseRU].left);
      imgDragging.style.pixelTop  = horseTop(horsesRU[iHorseRU].top);
    }

    // Вернем коня в основной слой
    imgDragging.style.zIndex = 0;

    // Сбросим ссылку на перемещаемого коня
    imgDragging = null;

  }
}
//================= Модальное окно: настройка программы =======
function setOptionRU()
{
  var args = new Array(numHorsesRU,dragAndDropRU);

  return window.showModalDialog("horseop.htm", args,
       "dialogWidth:300px;dialogHeight:340px;cеnter:yes;help:no;status:no");
}
