Программирование FEN

Тема в разделе "Машинное отделение", создана пользователем ProstoTak, 5 июл 2013.

  1. TopicStarter Overlay

    ProstoTak Старожил

    • Ветеран
    • Старожил
    Рег.:
    12.02.2006
    Сообщения:
    5.479
    Симпатии:
    123
    Репутация:
    1
    Оффлайн
    Народ, кто в теме. Возникла необходимость на PHP сгенерировать новый FEN на основе текущего FEN и заданного хода.
    Вот пример FEN
    Код:
    $fen='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
    и ход
    Код:
    $move='Nf1-g3';
    Нужно сделать функцию на PHP
    Код:
    function MoveFEN($fen,$move)
    Которая возвращает FEN полученный из передаваемых ей как параметры $fen и $move.
    Имеются ли у кого какие соображения?
  2. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.494
    Симпатии:
    3.126
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Расставляем фигуры на доске в соответствии с FEN, делаем ход (проверяя корректность?), кодируем обратно в FEN.
    Если есть готовый код для представления доски и делания ходов, я бы сделал именно так.
    Можно, наверное, и проще - но тогда придётся отрабатывать отдельно кучу граничных случаев с рокировками, превращениями, взятиями на проходе...

    Кстати, а на PHP есть играющие движки?
  3. TopicStarter Overlay

    ProstoTak Старожил

    • Ветеран
    • Старожил
    Рег.:
    12.02.2006
    Сообщения:
    5.479
    Симпатии:
    123
    Репутация:
    1
    Оффлайн
    Не знаю, не встречал. Наверное они медленные очень если есть :)

    С переносом фена на доску я тоже думал, но может можно проще? Кстати, проверять корректность кода и фена нет надобности. Всё это уже сделается до вызова функции.
  4. Scaramuccia Старожил

    • Участник
    • Старожил
    Рег.:
    13.01.2012
    Сообщения:
    3.182
    Симпатии:
    2.090
    Репутация:
    61
    Оффлайн
    Нотация хода, я надеюсь, полная? Иначе мы сразу умрем.
    План примерно такой:
    Нужно писать функцию добавляющую фигуру на доску и снимающую её.
    Это не очень сложно.
    Потом написать функцию которая делает ход - добавляет пустое место откуда ходим и ставит нашу фигуру туда где надо.
    Добавить рокировки - это просто.
    И взятие на проходе - это на удивление не сложно так как в fen'e есть информация можно ли какую-то пешку взять на проходе - следовательно можно провереить исключительно это поле.

    Важно не забыть поменять хвост fen'a - возможности рокировки + возможность взятия на проходе.

    PS К сожалению, я не пишу на php.
  5. TopicStarter Overlay

    ProstoTak Старожил

    • Ветеран
    • Старожил
    Рег.:
    12.02.2006
    Сообщения:
    5.479
    Симпатии:
    123
    Репутация:
    1
    Оффлайн
    Код:
    // - - - - - - - - - - - - - - -  - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - - - -
    function FenByXod($fen,$xod) {
     
      $afen      = explode(' ',$fen);
      $poza      = $afen[0];  $proxod    = $afen[3];
      $chejxod   = $afen[1];  $p50       = $afen[4];
      $rokirovka = $afen[2];  $nomerxoda = $afen[5];
     
      $doska=FenPozaToDoska($poza);
      $fg=$xod[0];
      if($fg=='R' || $fg=='N' || $fg=='B' || $fg=='Q' || $fg=='K')  { // - - - Ход фигурой - - -
        F_p1p2($xod,$p1,$p2);
        $rokirovka=ChangeRokirovka($rokirovka,$xod,$p2);
        $proxod='-';
        if($doska[$p2] !='0' ) $p50=0; else $p50++;
        if($chejxod=='b') { $nomerxoda++; $chejxod='w'; } else $chejxod='b';
        $fg=$doska[$p1]; $doska[$p1]='0'; $doska[$p2]=$fg;
        $poza=DoskaToFenPoza($doska);
        $fen=$poza.' '.$chejxod.' '.$rokirovka.' '.$proxod.' '.$p50.' '.$nomerxoda;
        return $fen;
      }
     
      if($fg>='a' && $fg<='h') {          // - - - Ход пешкой - - -
        P_p1p2($xod,$p1,$p2);
        $rokirovka=ChangeRokirovka($rokirovka,$xod,$p2);
        if($xod[4]!='1' && $xod[4]!='8') { // Без превращения
          if($proxod != '-' && $xod[3] == $proxod[0] && $xod[4] == $proxod[1]) $vp=1; else $vp=0;
          $p50=0;
          if(abs($p1-$p2)>12) $proxod=$xod[0].(($xod[1]+$xod[4])/2);  else $proxod='-';
          if($chejxod=='b') { $nomerxoda++; $chejxod='w'; } else $chejxod='b';
          $fg=$doska[$p1]; $doska[$p1]='0'; $doska[$p2]=$fg;
     
          if($vp==1) {                    // Взятие на проходе
            if($chejxod=='w') $doska[$p2-8]=0; else $doska[$p2+8]=0;
          }
        }
        else {                            // С превращением
          $p50=0; $proxod='-';
          $fg=$xod[5];if($chejxod=='b') $fg=strtolower($fg);
          if($chejxod=='b') { $nomerxoda++; $chejxod='w'; } else $chejxod='b';
          $doska[$p1]='0'; $doska[$p2]=$fg;
        }
        $poza=DoskaToFenPoza($doska);
        $fen=$poza.' '.$chejxod.' '.$rokirovka.' '.$proxod.' '.$p50.' '.$nomerxoda;
        return $fen;
      }
     
      if($xod == 'O-O' )  { // - - - Короткая рокировка - - -
        $proxod='-'; $p50++;
        if($chejxod=='b') { $nomerxoda++; $chejxod='w'; } else $chejxod='b';
        if($chejxod=='b') {
          $doska[60]='0'; $doska[61]='R'; $doska[62]='K'; $doska[63]='0';
          $rokirovka=str_replace('K','',$rokirovka);
          $rokirovka=str_replace('Q','',$rokirovka);
        }
        else {
          $doska[4]='0'; $doska[5]='r'; $doska[6]='k'; $doska[7]='0';
          $rokirovka=str_replace('k','',$rokirovka);
          $rokirovka=str_replace('q','',$rokirovka);
        }
        if($rokirovka=='') $rokirovka='-';
        $poza=DoskaToFenPoza($doska);
        $fen=$poza.' '.$chejxod.' '.$rokirovka.' '.$proxod.' '.$p50.' '.$nomerxoda;
        return $fen;
      }
     
      if($xod == 'O-O-O' ) { // - - - Длинная рокировка - - -
        $proxod='-'; $p50++;
        if($chejxod=='b') { $nomerxoda++; $chejxod='w'; } else $chejxod='b';
        if($chejxod=='b') {
          $doska[56]='0'; $doska[58]='K'; $doska[59]='R'; $doska[60]='0';
          $rokirovka=str_replace('K','',$rokirovka);
          $rokirovka=str_replace('Q','',$rokirovka);
        }
        else {
          $doska[0]='0'; $doska[2]='k'; $doska[3]='r'; $doska[4]='0';
          $rokirovka=str_replace('k','',$rokirovka);
          $rokirovka=str_replace('q','',$rokirovka);
        }
        if($rokirovka=='') $rokirovka='-';
        $poza=DoskaToFenPoza($doska);
        $fen=$poza.' '.$chejxod.' '.$rokirovka.' '.$proxod.' '.$p50.' '.$nomerxoda;
        return $fen;
      }
      return $fen;
    }
    //————————————————————————————————————————————————————
    function F_p1p2($xod,&$p1,&$p2) {
    $v1=Ord($xod[1])-96;  $g1=$xod[2]*1;
    $v2=Ord($xod[4])-96;  $g2=$xod[5]*1;
    $p1=(9-$g1-1)*8+$v1-1; $p2=(9-$g2-1)*8+$v2-1;
    }
    //————————————————————————————————————————————————————
    function P_p1p2($xod,&$p1,&$p2) {
    $v1=Ord($xod[0])-96;  $g1=$xod[1]*1;
    $v2=Ord($xod[3])-96;  $g2=$xod[4]*1;
    $p1=(9-$g1-1)*8+$v1-1; $p2=(9-$g2-1)*8+$v2-1;
    }
    //————————————————————————————————————————————————————
    function ChangeRokirovka($r,$xod,$p2) {
    if($xod[1]=='e' && $xod[2]=='1') { $r=str_replace('K','',$r); $r=str_replace('Q','',$r); }
    if($xod[1]=='a' && $xod[2]=='1') { $r=str_replace('Q','',$r); }
    if($xod[1]=='h' && $xod[2]=='1') { $r=str_replace('K','',$r); }
    if($xod[1]=='e' && $xod[2]=='8') { $r=str_replace('k','',$r); $r=str_replace('q','',$r); }
    if($xod[1]=='a' && $xod[2]=='8') { $r=str_replace('q','',$r); }
    if($xod[1]=='h' && $xod[2]=='8') { $r=str_replace('k','',$r); }
    if($p2==0)  $r=str_replace('q','',$r);
    if($p2==7)  $r=str_replace('k','',$r);
    if($p2==56) $r=str_replace('Q','',$r);
    if($p2==63) $r=str_replace('K','',$r);
    if($r=='')  $r='-'; return $r;
    }
    //————————————————————————————————————————————————————
    function FenPozaToDoska($poza) {
      $doska='';
      for($i=0;$i<strlen($poza);$i++) {
        $c=$poza[$i];
        if($c>='1' && $c<='8') { for($j=1;$j<=$c;$j++) $doska.='0'; continue; }
        if($c != '/') $doska.=$c;
      }
      return $doska;
    }
    //————————————————————————————————————————————————————
    function DoskaToFenPoza($doska) {
      $poza=''; $pusto=0;
     
      for($i=0;$i<=63;$i++) {
        if($doska[$i]=='0') $pusto++;
        if((($i+1) % 8)==0) {
          if($pusto>0) $poza.=$pusto; $pusto=0;
          if($doska[$i] != '0') $poza.=$doska[$i];
          $poza.='/';
        }
        else {
          if($doska[$i] != '0') {
            if($pusto>0) $poza.=$pusto;
            $pusto=0;    $poza.=$doska[$i];
          }
        }
      }
      return rtrim($poza,'/');
    }
    //————————————————————————————————————————————————————
    
    Вот наваял. Жду идей по улучшению.
  6. TopicStarter Overlay

    ProstoTak Старожил

    • Ветеран
    • Старожил
    Рег.:
    12.02.2006
    Сообщения:
    5.479
    Симпатии:
    123
    Репутация:
    1
    Оффлайн
    Конечно. Умирать никому не хочется :)
  7. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.494
    Симпатии:
    3.126
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    А вот как бы это выглядело в Греке.
    Почувствуйте разницу :)
    Код:
    string NewFen(const string& oldFen, Move mv)
    {
      Position tmp;
      if (tmp.SetFen(oldFen) && tmp.MakeMove(mv))
        return tmp.GetFen();
      else
        return "error";
    }
  8. TopicStarter Overlay

    ProstoTak Старожил

    • Ветеран
    • Старожил
    Рег.:
    12.02.2006
    Сообщения:
    5.479
    Симпатии:
    123
    Репутация:
    1
    Оффлайн
    Ну если не смотреть на реализацию класса...тогда канешно :)
  9. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.494
    Симпатии:
    3.126
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Ага. Называется "code reuse" :)
  10. east-or-west Зарегистрирован

    Рег.:
    12.06.2013
    Сообщения:
    1
    Симпатии:
    0
    Репутация:
    0
    Оффлайн
    Еще один вариант повторного использования кода - http://code.google.com/p/phpcheckmate. Реализован класс Game. Преобразуем FEN в позицию. Добавляем ход (с проверкой легальности при желании) по make_move. Обратно преобразуем в FEN.

Поделиться этой страницей