Нужна помощь с действительными конем в шахматах


В прошлые выходные я писала короткие PHP-функцию, которая принимает начиная двигаться и возвращает действительный рыцарь площадей для этого.

<?php

/* get's starting move and returns valid knight moves */

echo GetValidKnightSquares('e4');

function GetValidKnightSquares($strStartingMove) {

  $cb_rows = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8);
  $valids  = array(array(-1, -2), array(-2, -1), array(-2, 1), array(-1, 2), array(1, 2), array(2, 1), array(2, -1), array(1, -2));

  $row = substr($strStartingMove, 0, 1);
  $col = substr($strStartingMove, 1, 1);

  $current_row = $cb_rows[$row];
  if(!in_array($current_row, $cb_rows)) {
    die("Hey, use chars from a to h only!");
  }

  $current_col = $col;
  if($current_col > 8) {
    die("Hey, use numbers from 1 to 8 only!");
  }

  $valid_moves = '';

  foreach ($valids as $valid) {
    $new_valid_row = $current_row + $valid[0];
    $new_valid_col = $current_col + $valid[1];

    if(($new_valid_row <= 8 && $new_valid_row > 0) && ($new_valid_col <= 8 && $new_valid_col > 0)) {
      $row_char = array_search($new_valid_row, $cb_rows);
      $valid_moves .= $row_char . "$new_valid_col ";
    }
  }

  return "Valid knight moves for knight on $strStartingMove are: $valid_moves";
} 

?>

Не могли бы вы взглянуть на него и поделитесь своими мыслями об этом? Код может также быть найден здесь.


Я выступила с критикой по поводу кода. Один парень сказал, что это лажа, слишком долго и не "умных" достаточно. Поэтому мне нужно второе мнение на это, анализ кода, если вам нравится. Я думаю, что есть место для улучшения (всегда), но для меня это был первый раз, когда я закодировал что-то связанное с шахматами. Я нашел нечто подобное, что привлекло мое внимание:

if ((abs(newX-currentX)==1 and abs(newY-currentY)==2) or (abs(newX-currentX)==2 and abs(newY-currentY)==1)) {
  /* VALID MOVE FOR A KNIGHT */
}
else {
  /* INVALID MOVE FOR A KNIGHT */
}


2387
4
php
задан 1 июня 2011 в 12:06 Источник Поделиться
Комментарии
3 ответа

Во-первых, функцию GetValidKnightSquares не стоит переводить доске местах. Любой код, который выполняет отдельную операцию и может быть названо, должны быть извлечены в собственную функцию. Это делает все намного легче читать и понимать. Имя вещи.

Во-вторых, я бы, наверное, использовать любые структуры данных, которые вы выбираете для вашей системной платы для определения допустимых ходов на доске. Структуре я собираюсь выбрать выглядит так:

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, "8a", "8b", "8c", "8d", "8e", "8f", "8g", "8h", -1,
-1, "7a", "7b", "7c", "7d", "7e", "7f", "7g", "7h", -1,
-1, "6a", "6b", "6c", "6d", "6e", "6f", "6g", "6h", -1,
-1, "5a", "5b", "5c", "5d", "5e", "5f", "5g", "5h", -1,
-1, "4a", "4b", "4c", "4d", "4e", "4f", "4g", "4h", -1,
-1, "3a", "3b", "3c", "3d", "3e", "3f", "3g", "3h", -1,
-1, "2a", "2b", "2c", "2d", "2e", "2f", "2g", "2h", -1,
-1, "1a", "1b", "1c", "1d", "1e", "1f", "1g", "1h", -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1

Это одномерный массив, который представляет собой ряды и файлы двумерной доске. Отрицательных там коврик совета и сделать его легче определить, когда кусок вышел из игры. (Мы увидим это позже.) Этот тип данных структура называется почтовый ящик (т. к. какой-то старик думал, что это выглядело как один, я думаю), и очень часто в шахматном программировании.

Вот как создать это:

// converts an index in the mailbox into its corresponding value in algebraic notation
function i2an($i) {
$files = "abcdefgh";
return 10 - floor($i / 10) . $files[($i % 10) - 1];
}

function generateEmptyBoard() {
$row = array();
for($i = 0; $i < 120; $i++) {
$row[] = ($i < 20 || $i > 100 || !($i % 10) || $i % 10 == 9)
? -1
: i2an($i);
}
return $row;
}

Это дает нам время мы видели выше. Все что осталось-это использовать его:

function knightMoves($square, $board) {
$i = an2i($square);
$moves = array();
foreach(array(8, -8, 12, -12, 19, -19, 21, -21) as $offset) {
$move = $board[$i + $offset];
if ($move != -1) {
$moves[] = $move;
}
}
return $moves;
}

// converts a position in algebraic notation into its location in the mailbox
function an2i($square) {
return (10 - $square[0]) * 10 + strpos("abcdefgh", $square[1]) + 1;
}

Обратите внимание, что почтовый ящик границ сделать это очень легко сказать, когда мы перешли к позиции с доски.

Вот некоторые примеры:

$board = generateEmptyBoard();
print_r(knightMoves("1h", $board));
print_r(knightMoves("5b", $board));
print_r(knightMoves("6c", $board));

Выход:

$ php knights.php
Array
(
[0] => 2f
[1] => 3g
)
Array
(
[0] => 6d
[1] => 4d
[2] => 3a
[3] => 7c
[4] => 3c
[5] => 7a
)
Array
(
[0] => 5a
[1] => 7e
[2] => 5e
[3] => 7a
[4] => 4b
[5] => 8d
[6] => 4d
[7] => 8b
)

Что самое классное, вы можете использовать этот почтовый ящик в течение всего вашего приложения путем замены некоторых представлением фактических штук за названиями на внутренние элементы. Это полезно не только для своей узкой задачи, другими словами.

5
ответ дан 19 декабря 2013 в 01:12 Источник Поделиться

что по этому поводу?

function GetValidKnightSquares($strStartingMove){
$rowvals='abcdefgh';
$row_assoc=array_flip(str_split($rowvals));
$row = $strStartingMove[0]-1;
if(!strstr($rowvals,$row)){
die('invalid row');
}
$col = $strStartingMove[1];
if($col<1 || $col>7){
die('invalid column');
}
$srow=$row_assoc[$row];
$valid_moves=array(
$row_assoc[$srow+2].$col+1,
$row_assoc[$srow+2].$col-1,
$row_assoc[$srow-2].$col+1,
$row_assoc[$srow-2].$col-1,
$row_assoc[$srow+1].$col+2,
$row_assoc[$srow+1].$col-2,
$row_assoc[$srow-1].$col+2,
$row_assoc[$srow-1].$col-2,
);
return "Valid knight moves for knight on $strStartingMove are: ".implode(', ',$valid_moves);
}

1
ответ дан 1 июня 2011 в 12:06 Источник Поделиться

Другой способ:

function GetValidKnightSquares($strStartingMove){
$row_letters = array_combine(range(1,8),range('a','h'));
$row_numbers = array_flip($row_letters);
$row = $row_numbers[$strStartingMove[0]];
$col = $strStartingMove[1];

$valid_moves = array();
foreach( array( 1=>2, 2=>1 ) as $r=>$c )
foreach( array( -1, 1 ) as $r_sign )
foreach( array( -1, 1 ) as $c_sign )
$valid_moves[] = $row_letters[$row + $r * $r_sign].($col + $c * $c_sign);

// This line from trey's code is actually pretty neat.
return "Valid knight moves for knight on $strStartingMove are: ".implode(', ',$valid_moves);
}

1
ответ дан 1 июня 2011 в 01:06 Источник Поделиться