체크메이트를 확인하세요. 해결해야 할 또 다른 문제에 오신 것을 환영합니다! 체스와 코딩을 좋아한다면 이 앱이 바로 당신을 위한 것입니다! 오늘 우리는 왕이 전장에서 또 다른 하루를 살아남을 수 있도록 돕고, 또한 꽤 많은 코드를 작성할 것입니다.
체스판의 말 위치를 나타내는
8
x8
행렬 이 표시됩니다 . 보드에 있는 유일한 말은 검은색 킹과 다양한 흰색 말뿐입니다. 이 행렬이 주어지면 킹이 체크 상태에 있는지 확인하세요.
각 조각이 어떻게 움직이는지에 대한 자세한 내용은 다음을 참조하세요.
예를 들어, 다음 행렬이 주어지면:
...K.... ........ .B...... ......P. .......R ..N..... ........ .....Q..
비숍이 킹을 대각선으로 공격하고 있으므로 True
반환해야 합니다 .
각 조각의 시작 위치와 이동 세트가 주어지면 모든 조각의 가능한 모든 다음 움직임을 "쉽게" 계산할 수 있습니다.
그리고 그들 모두는 가능한 한 빨리 왕을 잡는 데 관심이 있기 때문에 그들의 다음 움직임은 흑왕을 잡는 것이 될 것이라고 추측할 수 있습니다. 그러므로 우리는 흑왕의 위치도 알고 있기 때문에 흑왕의 위치가 다른 말의 가능한 다음 움직임 중 하나인지 확인하면 됩니다 . 만약 그렇다면, 다음 흰색 턴 동안 흰색 조각은 흑색 왕을 잡기 위해 그곳으로 이동할 것입니다.
우리는 8x8 그래프에 있고(명확하게 말하면 다른 모든 치수는 동일한 방식으로 작동함) 각 조각의 시작 좌표를 가지고 있으므로 다음 이동 조각이 될 일련의 x, y 좌표를 만들 수 있습니다. 이를 위해 먼저 각 조각에 대한 클래스를 정의하고 좌표를 정의한 다음 거기에서 가능한 모든 움직임을 계산하는 규칙을 정의합니다.
Pawn부터 간단하게 시작해 보겠습니다. 그건 그렇고, 나는 이것을 Python 으로 작성하고 있습니다. 왜냐하면 Python은 현재 가장 인기 있는 언어 중 하나이고 틀림없이 누구라도 가장 읽기 쉬운 언어이기 때문입니다. 그래도 앞으로 따라갈 수 있는 수업이 무엇인지 알아야 합니다 .
간단히 설명하자면, 먼저 class Pawn
클래스를 정의하고 x,y
좌표를 __init__
. 그런 다음, 거기에서 가능한 이동 수를 계산하기 위해 possibleMoves
메서드를 정의합니다. 폰 이동은 상대적으로 쉽기 때문에 그리드 밖으로 이동하지 않는지 확인한 후 이동 moves
에 추가하고 moves
배열을 반환하기만 하면 됩니다. 특히 폰에 대해 여기서 주목해야 할 두 가지 사항은 다음과 같습니다.
우리는 검은 왕을 잡는 데 관심이 있기 때문에 의도적으로 일반적인 움직임을 건너뜁니다 . 폰은 대각선으로만 캡처할 수 있고 조각을 다른 방향으로 움직이는 데 관심이 없기 때문에 정상적인 움직임을 건너뛸 수 있습니다.
이제 print(Pawn(7,2).possibleMoves())
와 같이 좌표를 제공하고 possibleMoves
메서드를 호출하여 폰의 움직임을 간단히 확인할 수 있으며 [(6,3),(8,3)]
과 같은 결과를 얻어야 합니다. [(6,3),(8,3)]
.
또한 상단에서 그리드 차원을 변수로 정의한 것을 볼 수 있으므로 다른 차원의 보드에서 알고리즘을 실행하도록 이를 변경할 수 있습니다.
이제 타워로 가보겠습니다.
다시 한번, 좌표를 사용하여 Tower 클래스를 초기화하고 possibleMoves
함수를 정의합니다. 여기에서 가능한 모든 이동을 수집하기 위해 타워 두 축의 모든 점 범위를 지정하고 각 단일 좌표를 변수 moves
에 추가합니다. 이 변수는 모든 루프 후에 반환됩니다. 이전과 마찬가지로 타워 이동을 확인하려면 간단히 print(Tower(5,3).possibleMoves())
하면 다음과 같은 결과를 얻을 수 있습니다: [(1,3), (2,3), (3,3), ..., (5,8)]
.
Bishop의 움직임은 타워보다 더 복잡하므로 여기서 무슨 일이 일어나고 있는지 조금 설명할 수 있습니다. 기본적으로 시작 위치에서 시작하여 두 대각선 축의 점을 수집해야 합니다 . 클래스와 init 메소드를 선언한 후 이전과 마찬가지로 moves
와 축을 따라 이동하는 동안 수집한 점을 추적하는 데 사용되는 currentPos
두 개의 변수를 만듭니다. 이제 while
루프를 사용하여 그리드 외부로 이동하지 않는지 확인하고 이동하려는 위치에 따라 x
와 y
늘리거나 줄입니다 . 예를 들어, 시작 위치에서 왼쪽 위로 이동하려면 x
값을 증가시키면서 y
값을 감소시켜야 합니다. 오른쪽으로 아래로 이동하려면 x
값을 늘리고 y
값을 줄여야 합니다. 마지막으로 다시 한 번 moves
반환합니다.
알겠습니다. 여기서 무슨 일이 일어나고 있나요? 뭐, 생각해보면 퀸은 비숍과 타워를 합친 것과 같은 움직임을 가지고 있다 . 그녀는 여왕이라기보다는 탑 모양의 주교 메카봇에 더 가깝습니다. 이런 이유로 그녀의 동작을 코딩하는 것은 정말 간단합니다. 그녀의 클래스를 선언한 후 우리는 그녀의 possibleMoves
비숍과 타워의 가능한 이동으로 인한 이동의 통합 배열 로 정의합니다.
possibleMoves
함수에서 Bishop
및 Tower
인스턴스 클래스를 호출하는 동안 해당 매개변수 x
및 y
self.x, self.y
로 제공되므로 실제로는 퀸 좌표입니다.
기사는 나에게 가장 특별합니다. 그의 동작 세트는 "L"자 모양과 같이 이상하기 때문에 특별히 영리하거나 빠른 코딩 방법을 찾지 못했고 결국 시작 위치에서 가능한 8개의 동작을 각각 계산하여 동작을 하드 코딩하게 되었습니다.
왕에 관한 몇 가지 간단한 개념. 우리는 킹을 움직일 필요가 없고 그가 체크되었는지 여부만 알려주기 때문에 실제로 그의 move-set을 구현할 필요는 없습니다 . 그러나 기사 끝부분에서는 간략한 구현도 살펴보겠습니다. 또한 나중에 살펴보겠지만 코딩은 여왕의 이동 세트를 너프하는 것만큼 간단하지 않습니다. 따라서 지금은 그의 움직임을 건너뛰고 해결책을 살펴보겠습니다.
이제 간단히 두 개의 좌표로 변수 blackKing
생성합니다. 그런 다음 각 조각에 대해 방금 구축한 클래스의 인스턴스를 만들고 possibleMoves
메서드를 호출하여 전체 이동 집합을 계산합니다. 일단 그것을 얻으면 해당 이동 세트에 blackKing
좌표가 있는지 확인합니다. 만약 그렇다면 킹이 특정 조각에 의해 확인되었음을 인쇄합니다. 결과는 다음과 같습니다.
Pawn moves: [(8, 3), (6, 3)] Tower moves: [(1, 3), (2, 3), (3, 3), (4, 3), (6, 3), (7, 3), (8, 3), (5, 1), (5, 2), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8)] Check by the tower! Bishop moves: [(3, 8), (1, 6), (1, 8), (3, 6), (4, 5), (5, 4), (6, 3), (7, 2), (8, 1)] Queen moves: [(4, 3), (5, 4), (6, 5), (7, 6), (8, 7), (2, 1), (2, 3), (1, 4), (4, 1), (1, 2), (2, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (3, 1), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8)] Knight moves: [(4, 7), (4, 5), (8, 7), (8, 5), (5, 4), (7, 4), (7, 8), (5, 8)] Check by the knight!
왕이 아직 생존할 가능성이 있는지, 아니면 실제로 체크메이트인지 계산하고 싶다면 어떨까요? 이를 위해 우리는 왕의 이동 수를 계산해야 합니다.
조금 설명해보자. 먼저, 이전과 같이 클래스와 좌표를 정의합니다. 그런 다음 possibleMoves
메소드를 생성하고 왕의 가능한 동작을 코딩합니다(다시 말하지만 더 빠른 방법이 있다고 확신하지만 가능한 동작은 8개이므로…). 그런 다음 어떤 동작이 불법인지(보드 외부로 이동) 확인 하고 validMoves
만 반환합니다.
이제 왕이 아직 생존할 기회가 있는지 확인 하려면 가능한 이동 중 다른 이동 조각 세트에 없는 것이 있는지 확인해야 합니다. 이를 위해 우리는 단순히 킹 동작과 다른 동작을 반복합니다.
그러니 우리 왕이 살아남을 희망은 아직 남아있습니다! 그 사람에겐 행운일 것 같아요…
우선, 각 조각은 클래스의 인스턴스 이므로 해당 인스턴스를 초기화하는 데 걸리는 시간을 고려해야 합니다.
퀸은 타워와 비숍의 움직임이 결합된 세트가 필요합니다. 시간 복잡도를 평가하는 동안 최악의 시나리오에 초점을 맞춰야 하므로 비숍의 TC가 타워의 TC보다 우선합니다. 따라서 우리는 여왕에 대해서도 O(n)의 tc를 고려해야 합니다.
마침내 왕은 하드 코딩된 동작 세트를 갖게 되었지만 for 루프를 사용하는 검증 프로세스도 포함되었습니다 . 따라서 기술적으로 킹의 움직임 세트가 상대적으로 작더라도 보드에서의 위치에 따라 그의 tc를 O(n)으로 간주해야 합니다.
이 시점에서 우리는 각 조각에 대해 for 루프를 사용하여 Black king의 체크 상태를 확인하고 인쇄합니다 . 이는 tc가 일정한 경우 문제가 되지 않습니다(예를 들어 타워를 예로 들자면 14개의 동작을 계산한 다음 최대 14번을 반복하므로 고정 시간으로도 간주할 수 있습니다). 그래도 tc가 O(n) 이상이면 문제가 발생할 것입니다. 이동 횟수가 증가하는 동안 루프도 증가하므로 루프를 추가하기 때문입니다.
마지막으로, 체크 메이트를 확인하기 위해 이중(내부) for 루프를 사용합니다 . 이는 킹의 이동 횟수와 다른 말의 이동에 따라 확실히 O(n²)의 tc가 될 것입니다.