python으로 체스 게임 작성 [4일째]
17465 단어 codenewbiepython
우리는 에서 효과적인 이동 검사 테스트 세트를 끝냈는데, 흔히 볼 수 있는 장면 (목표 블록이 경계를 초과하거나 같은 색깔의 바둑알이 차지함) 과 rook 이동에 사용된다.
오늘 우리는 칠판 위에서 차 한 대를 옮기기로 결정했다.
우리는 이 인터페이스를 정의했다.
def move(board, piece, target_rank, target_file):
pass
우리가 그것을 실현하기 위해 무엇을 필요로 하는지 고려할 때, 우리는 하나의 동작이 효과가 있는지 검사하는 것이 부족하다는 것을 깨닫고, 효과적인 부분이 어디에 있는지 알아야 한다.is_valid_move
은 이 위치를 검증검사의 일부로 계산하기 때문에 검증방법 이외의 두 번째 방법이 아닌 둘을 결합시키는 것이 더 의미가 있다.솔직히 말해서, 나는 우리가 결국 이렇게 할 것이라는 것을 알고 있지만, 나는 그로 하여금 스스로 생각하게 했다. 이것은 학습 과정의 일부분이다.또 다른 장점은 테스트의 가치를 보여주는 것이다. 우리가 다른 내용을 되돌리기 위해 방법을 바꾼 후에 우리는 기존의 테스트에 대해 약간의 변경을 했다. 테스트가 통과되었을 때 우리는 자신감을 가지게 되고 기능이 어떠한 후퇴도 일으키지 않을 것이다.
다음은 우리가 바꾼 것이다.
def find_valid_move(board, piece, target_rank, target_file):
# out of bounds
if target_rank < 0 or target_rank > 7:
return -1, -1
if target_file < 0 or target_file > 7:
return -1, -1
# piece with same color is in the target square
if board[target_rank][target_file][0] == piece[0]:
return -1, -1
if piece in ("WR", "BR"):
return find_valid_rook_move(board, piece, target_rank, target_file)
return -1, -1
def find_valid_rook_move(board, piece, target_rank, target_file):
found_rank = -1
found_file = -1
for i in range(8):
if board[target_rank][i] == piece:
found_rank = target_rank
found_file = i
break
if found_rank == -1:
for i in range(8):
if board[i][target_file] == piece:
found_rank = i
found_file = target_file
break
if found_rank < 0 or found_file < 0:
return -1, -1
if found_rank == target_rank:
start_file = min(target_file+1, found_file+1)
end_file = max(target_file, found_file)
for i in range(start_file, end_file):
if board[target_rank][i] != EMPTY:
return -1, -1
else: # found_file == target_file
start_rank = min(target_rank+1, found_rank+1)
end_rank = max(target_rank, found_rank)
for i in range(start_rank, end_rank):
if board[i][target_file] != EMPTY:
return -1, -1
return found_rank, found_file
이것은 완전히 같은 논리입니다. 유효한 부분을 찾지 못했을 때만 되돌아갑니다. (-1, -1) 유효한 부분을 찾으면 되돌아갑니다. (find rank,find file)다음은 다음과 같이
move
로직을 구현했습니다.def move(board, piece, target_rank, target_file):
found_rank, found_file = find_valid_move(board, piece,
target_rank, target_file)
if (found_rank, found_file) != (-1, -1):
board[target_rank][target_file] = piece
board[found_rank][found_file] = EMPTY
return True
return False
다음은 move
이 예상대로 작동하는지 확인하기 위한 소형 수동 테스트입니다.board = create_board()
board[1][0] = EMPTY
result = move(board, "WR", 5, 0)
print_board(board)
놀라운 결과: ---- ---- ---- ---- ---- ---- ---- ----
8 | BR | BN | BB | BQ | BK | BB | BN | BR |
---- ---- ---- ---- ---- ---- ---- ----
7 | BP | BP | BP | BP | BP | BP | BP | BP |
---- ---- ---- ---- ---- ---- ---- ----
6 | WR | | | | | | | |
---- ---- ---- ---- ---- ---- ---- ----
5 | WR | | | | | | | |
---- ---- ---- ---- ---- ---- ---- ----
4 | WR | | | | | | | |
---- ---- ---- ---- ---- ---- ---- ----
3 | WR | | | | | | | |
---- ---- ---- ---- ---- ---- ---- ----
2 | | WP | WP | WP | WP | WP | WP | WP |
---- ---- ---- ---- ---- ---- ---- ----
1 | | WN | WB | WQ | WK | WB | WN | WR |
---- ---- ---- ---- ---- ---- ---- ----
a b c d e f g h
12yo는 이 점을 이해할 수 없지만, 나는 곧 무슨 일이 일어났는지 깨달았다. 나는 더 잘 알아야 한다.아이고.다음 명령을 사용하여 보드를 초기화했습니다.board = [[EMPTY]*8]*8
이것은 목록을 만들고 8번 복사합니다.우리가 5위를 바꿀 때, 그것은 모든 중간 줄에서 바뀌었다. (다른 줄은 조각이 포함된 줄로 바뀌었다.)크게 틀리다.그러지 마.12yo는 어떤 부분에 문제가 생겼는지, 왜 문제가 생겼는지 이해할 때 어려움을 겪었다. 그래서 나는 간단한 예시를 만들어서 설명했다.
sub_list = [1,2,3]
test_list = [sub_list]*3
print(test_list)
sub_list[0] = 5
print(test_list)
그는 "아, 그래...모든 목록의 항목을 바로 바꿀 거야."라고 말했기 때문에 나는 그가 이해했다고 생각한다.출력:
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[5, 2, 3], [5, 2, 3], [5, 2, 3]]
일단 우리가 이 문제를 해결하면, 그것은 정상적으로 일할 것이다.12yo는 다음 테스트를 작성했습니다.
def test_move_rook():
board = create_board()
board[1][0] = EMPTY
result = move(board, "WR", 5, 0)
assert result
print("test_move_rook passed")
괜찮다그러나 나는 그에게 이것이 우리가 수동으로 테스트를 실행할 때 본 문제를 발견할 수 있느냐고 물었다.그는'아니야'라고 말하고 싶었다.테스트에 expected_board
비트를 추가했습니다.def test_move_rook():
board = create_board()
board[1][0] = EMPTY
expected_board = create_board()
expected_board[1][0] = EMPTY
expected_board[0][0] = EMPTY
expected_board[5][0] = "WR"
result = move(board, "WR", 5, 0)
assert result
assert board == expected_board
print("test_move_rook passed")
곧 올 거라는 건 알지만, 너무 빨리 합류하고 싶지 않아...그러나 지금은 때가 되었다. 만약 두 개의 효과적인 장면이 있다면 무슨 일이 일어날까?12yo는 가능한 위치를 계산하는 것이 아니라 우리가 공작물을 어디에서 이동할 것인지, 목표를 미리 지정하는 나의 최초의 생각을 받아들이지 않은 것을 후회하기 시작했다. 그러나 나는 지금 포기하지 않을 것이다.그는 두 개의 일치하는 바둑알이 있을 때, 유저는 바둑알의 등급을 지정하지만, 일을 간단하게 하기 위해서, 나는 우리가 등급을 지정하는 것을 건의한다.그가 본 바와 같이, 나의 건의는 통상적으로 합리적이어서, 그는 이 생각을 받아들이기로 결정했다.
find_valid_rook_move
방법을 다음과 같이 변경합니다.source_rank
및 source_file
을 추가했습니다.found_pieces
목록에 추가했습니다.source_rank
과 source_file
이 일치하는 것을 찾아보세요.def find_valid_rook_move(board, piece, target_rank, target_file, source_rank=-1, source_file=-1):
found_pieces = []
for i in range(8):
if board[target_rank][i] == piece:
found_rank = target_rank
found_file = i
found_pieces.append((found_rank, found_file))
for i in range(8):
if board[i][target_file] == piece:
found_rank = i
found_file = target_file
found_pieces.append((found_rank, found_file))
if len(found_pieces) == 0:
return -1, -1
# don't know which item to choose
found_rank = -1
found_file = -1
if (len(found_pieces) > 1):
if source_rank < 0 or source_file < 0:
return -1, -1
for rank, file in found_pieces:
if rank == source_rank and file == source_file:
found_rank = rank
found_file = file
else:
found_rank, found_file = found_pieces[0]
if (found_rank, found_file) == (-1, -1):
return -1, -1
if found_rank == target_rank:
start_file = min(target_file+1, found_file+1)
end_file = max(target_file, found_file)
for i in range(start_file, end_file):
if board[target_rank][i] != EMPTY:
return -1, -1
else: # found_file == target_file
start_rank = min(target_rank+1, found_rank+1)
end_rank = max(target_rank, found_rank)
for i in range(start_rank, end_rank):
if board[i][target_file] != EMPTY:
return -1, -1
return found_rank, found_file
테스트가 하나 더 추가되었습니다.def test_double_move_rook():
board = create_board()
board[1][0] = EMPTY
board[0][7] = EMPTY
board[5][0] = "WR"
result = move(board, "WR", 3, 0)
assert not result
expected_board = create_board()
expected_board[1][0] = EMPTY
expected_board[0][7] = EMPTY
expected_board[5][0] = "WR"
expected_board[3][0] = "WR"
expected_board[0][0] = EMPTY
result = move(board, "WR", 3, 0, 0, 0)
assert result
assert board == expected_board
print("test_double_move_rook passed")
우리가 검사해야 할 장면이 하나 더 있는데, 나는 이미 그것이 통과하지 못할 것이라는 것을 알고 있다.만약 회로판에 일치하는 부품이 두 개 있는데, 그 중 하나가 막히면 어떤 상황이 발생합니까?나는 12yo에게 테스트를 작성하라고 한 후에 실패의 원인을 찾아내려고 했다. ...
board = create_board()
board[0][7] = EMPTY
board[5][0] = "WR"
expected_board = create_board()
expected_board[0][7] = EMPTY
expected_board[3][0] = "WR"
expected_board[0][0] = "WR"
result = move(board, "WR", 3, 0)
assert result
assert board == expected_board
우리는 print
의 서로 다른 위치에 find_valid_rook_move
명령을 추가했다. 우리는 우리가 공작물을 선택한 후에 유효성을 검사했기 때문에 우리가 충분한 정보(즉 source_rank
과 source_file
이 너무 이르다는 결론을 얻었다.우리가
valid_pieces
과 source_rank
이 필요하다는 것을 검증하기 전에 우리는 논리를 바꾸었고 source_file
을 찾았으며 성공했다(12yo는 내가 논리를 완성하도록 인도한 후에 이러한 변경을 했다)👏):def find_valid_rook_move(board, piece, target_rank, target_file, source_rank=-1, source_file=-1):
found_pieces = []
for i in range(8):
if board[target_rank][i] == piece:
found_rank = target_rank
found_file = i
found_pieces.append((found_rank, found_file))
for i in range(8):
if board[i][target_file] == piece:
found_rank = i
found_file = target_file
found_pieces.append((found_rank, found_file))
if len(found_pieces) == 0:
return -1, -1
valid_pieces = []
for found_rank, found_file in found_pieces:
is_valid = True
if found_rank == target_rank:
start_file = min(target_file+1, found_file+1)
end_file = max(target_file, found_file)
for i in range(start_file, end_file):
if board[target_rank][i] != EMPTY:
is_valid = False
break
else: # found_file == target_file
start_rank = min(target_rank+1, found_rank+1)
end_rank = max(target_rank, found_rank)
for i in range(start_rank, end_rank):
if board[i][target_file] != EMPTY:
is_valid = False
break
if is_valid:
valid_pieces.append((found_rank, found_file))
# don't know which item to choose
found_rank = -1
found_file = -1
if len(valid_pieces) > 1:
if source_rank < 0 or source_file < 0:
return -1, -1
for rank, file in valid_pieces:
if rank == source_rank and file == source_file:
found_rank = rank
found_file = file
elif len(valid_pieces) == 1:
found_rank, found_file = valid_pieces[0]
return found_rank, found_file
현재 우리는 모두 템플릿을 설치하여 모든 다른 부분을 이동할 수 있기 때문에 나는 우리가 다음 부분을 더욱 빨리 완성할 수 있기를 바란다.다음에 또 오세요!
오늘의 최종 코드(수정된 테스트 포함):
EMPTY = " "
def print_board(board):
row_number = 8
print(" ", end="")
print(" ----"*8)
for row in reversed(board):
print(row_number, end=" ")
row_number -= 1
for cell in row:
print("| {} ".format(cell), end="")
print("|")
print(" ", end="")
print(" ----"*8)
print(" ", end="")
for letter in ['a','b','c','d','e','f','g','h']:
print(" {} ".format(letter), end="")
print("")
def create_board():
board = []
board.append(["WR","WN","WB","WQ","WK","WB","WN","WR"])
board.append(["WP","WP","WP","WP","WP","WP","WP","WP"])
for i in range(2, 6):
board.append([EMPTY]*8)
board.append(["BP","BP","BP","BP","BP","BP","BP","BP"])
board.append(["BR","BN","BB","BQ","BK","BB","BN","BR"])
return board
def find_valid_move(board, piece, target_rank, target_file, source_rank=-1, source_file=-1):
# out of bounds
if target_rank < 0 or target_rank > 7:
return -1, -1
if target_file < 0 or target_file > 7:
return -1, -1
# piece with same color is in the target cell
if board[target_rank][target_file][0] == piece[0]:
return -1, -1
if piece in ("WR", "BR"):
return find_valid_rook_move(board, piece, target_rank, target_file, source_rank, source_file)
return -1, -1
def find_valid_rook_move(board, piece, target_rank, target_file, source_rank=-1, source_file=-1):
found_pieces = []
for i in range(8):
if board[target_rank][i] == piece:
found_rank = target_rank
found_file = i
found_pieces.append((found_rank, found_file))
for i in range(8):
if board[i][target_file] == piece:
found_rank = i
found_file = target_file
found_pieces.append((found_rank, found_file))
if len(found_pieces) == 0:
return -1, -1
valid_pieces = []
for found_rank, found_file in found_pieces:
is_valid = True
if found_rank == target_rank:
start_file = min(target_file+1, found_file+1)
end_file = max(target_file, found_file)
for i in range(start_file, end_file):
if board[target_rank][i] != EMPTY:
is_valid = False
break
else: # found_file == target_file
start_rank = min(target_rank+1, found_rank+1)
end_rank = max(target_rank, found_rank)
for i in range(start_rank, end_rank):
if board[i][target_file] != EMPTY:
is_valid = False
break
if is_valid:
valid_pieces.append((found_rank, found_file))
# don't know which item to choose
found_rank = -1
found_file = -1
if len(valid_pieces) > 1:
if source_rank < 0 or source_file < 0:
return -1, -1
for rank, file in valid_pieces:
if rank == source_rank and file == source_file:
found_rank = rank
found_file = file
elif len(valid_pieces) == 1:
found_rank, found_file = valid_pieces[0]
return found_rank, found_file
def move(board, piece, target_rank, target_file, source_rank=-1, source_file=-1):
found_rank, found_file = find_valid_move(board, piece,
target_rank, target_file, source_rank, source_file)
if (found_rank, found_file) != (-1, -1):
board[target_rank][target_file] = piece
board[found_rank][found_file] = EMPTY
return True
return False
# ----------------------- tests -------------------
def test_move_rook():
board = create_board()
board[1][0] = EMPTY
expected_board = create_board()
expected_board[1][0] = EMPTY
expected_board[0][0] = EMPTY
expected_board[5][0] = "WR"
result = move(board, "WR", 5, 0)
assert result
assert board == expected_board
print("test_move_rook passed")
def test_double_move_rook():
board = create_board()
board[1][0] = EMPTY
board[0][7] = EMPTY
board[5][0] = "WR"
result = move(board, "WR", 3, 0)
assert not result
expected_board = create_board()
expected_board[1][0] = EMPTY
expected_board[0][7] = EMPTY
expected_board[5][0] = "WR"
expected_board[3][0] = "WR"
expected_board[0][0] = EMPTY
result = move(board, "WR", 3, 0, 0, 0)
assert result
assert board == expected_board
board = create_board()
board[0][7] = EMPTY
board[5][0] = "WR"
expected_board = create_board()
expected_board[0][7] = EMPTY
expected_board[3][0] = "WR"
expected_board[0][0] = "WR"
result = move(board, "WR", 3, 0)
assert result
assert board == expected_board
print("test_double_move_rook passed")
def test_is_rank_valid():
board = create_board()
result = find_valid_move(board, "xx", 22, 4)
assert result == (-1, -1)
result = find_valid_move(board, "xx", -2020, 4)
assert result == (-1, -1)
print("test_is_rank_valid passed")
def test_is_file_valid():
board = create_board()
result = find_valid_move(board, "xx", 0, 22)
assert result == (-1, -1)
result = find_valid_move(board, "xx", 0, -2020)
assert result == (-1, -1)
print("test_is_file_valid passed")
def test_is_target_square_taken():
board = create_board()
result = find_valid_move(board, "Wx", 0, 1)
assert result == (-1, -1)
print("test_is_target_square_taken passed")
def test_rook_is_blocked():
board = create_board()
result = find_valid_rook_move(board, "BR", 5, 0)
assert result == (-1, -1)
board[7][5] = EMPTY
result = find_valid_rook_move(board, "BR", 7, 5)
assert result == (-1, -1)
print("test_rook_is_blocked passed")
def test_rook_is_not_blocked():
board = create_board()
board[1][0] = EMPTY
result = find_valid_rook_move(board, "WR", 2, 0)
assert result == (0,0)
board[0][1] = EMPTY
result = find_valid_rook_move(board, "WR", 0, 1)
assert result == (0,0)
print("test_rook_is_not_blocked passed")
def run_tests():
test_is_rank_valid()
test_is_file_valid()
test_is_target_square_taken()
test_rook_is_blocked()
test_rook_is_not_blocked()
test_move_rook()
test_double_move_rook()
run_tests()
Reference
이 문제에 관하여(python으로 체스 게임 작성 [4일째]), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rinaarts/writing-a-chess-game-in-python-day-4-1o84텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)