Initial commit

This commit is contained in:
BarsTigerMeowcat
2020-01-26 12:46:16 +02:00
commit b01c9d869f
24 changed files with 2054 additions and 0 deletions

View File

@@ -0,0 +1,259 @@
# "Реверси": клон "Отелло".
import random
import sys
WIDTH = 8 # Игровое поле содержит 8 клеток по ширине.
HEIGHT = 8 # Игровое поле содержит 8 клеток по высоте.
def drawBoard(board):
# Вывести игровое поле, переданное этой функции. Ничего не возвращать.
print(' 12345678')
print(' +--------+')
for y in range(HEIGHT):
print('%s|' % (y+1), end='')
for x in range(WIDTH):
print(board[x][y], end='')
print('|%s' % (y+1))
print(' +--------+')
print(' 12345678')
def getNewBoard():
# Создать структуру данных нового чистого игрового поля.
board = []
for i in range(WIDTH):
board.append([' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '])
return board
def isValidMove(board, tile, xstart, ystart):
# Вернуть False, если ход игрока в клетку с координатами xstart, ystart — недопустимый.
# Если это допустимый ход, вернуть список клеток, которые "присвоил" бы игрок, если бы сделал туда ход.
if board[xstart][ystart] != ' ' or not isOnBoard(xstart, ystart):
return False
if tile == 'Х':
otherTile = 'О'
else:
otherTile = 'Х'
tilesToFlip = []
for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]:
x, y = xstart, ystart
x += xdirection # Первый шаг в направлении x
y += ydirection # Первый шаг в направлении y
while isOnBoard(x, y) and board[x][y] == otherTile:
# Продолжать двигаться в этом направлении x и y.
x += xdirection
y += ydirection
if isOnBoard(x, y) and board[x][y] == tile:
#Естьфишки,которыеможноперевернуть.Двигатьсявобратномнаправлениидодостиженияисходнойклетки,отмечаявсефишкинаэтомпути.
while True:
x -= xdirection
y -= ydirection
if x == xstart and y == ystart:
break
tilesToFlip.append([x, y])
if len(tilesToFlip) == 0: # Если ни одна из фишек не перевернулась, это недопустимый ход
return False
return tilesToFlip
def isOnBoard(x, y):
# Вернуть True, если координаты есть на игровом поле.
return x >= 0 and x <= WIDTH - 1 and y >= 0 and y <= HEIGHT - 1
def getBoardWithValidMoves(board, tile):
# Вернуть новое поле с точками, обозначающими допустимые ходы, которые может сделать игрок.
boardCopy = getBoardCopy(board)
for x, y in getValidMoves(boardCopy, tile):
boardCopy[x][y] = '.'
return boardCopy
def getValidMoves(board, tile):
# Вернуть список списков с координатами x и y допустимых ходов для данного игрока на данном игровом поле.
validMoves = []
for x in range(WIDTH):
for y in range(HEIGHT):
if isValidMove(board, tile, x, y) != False:
validMoves.append([x, y])
return validMoves
def getScoreOfBoard(board):
# Определить количество очков, подсчитав фишки. Вернуть словарь с ключами 'Х' и 'О'.
xscore = 0
oscore = 0
for x in range(WIDTH):
for y in range(HEIGHT):
if board[x][y] == 'Х':
xscore += 1
if board[x][y] == 'О':
oscore += 1
return {'Х':xscore, 'О':oscore}
def enterPlayerTile():
# Позволить игроку ввести выбранную фишку.
# Возвращает список с фишкой игрока в качестве первого элемента и фишкой компьютера в качестве второго.
tile = ''
while not (tile == 'Х' or tile == 'О'):
print('Вы играете за Х или О?')
tile = input().upper()
# Первый элемент в списке — фишка игрока, второй элемент — фишка компьютера.
if tile == 'Х':
return ['Х', 'О']
else:
return ['О', 'Х']
def whoGoesFirst():
# Случайно выбрать, кто ходит первым.
if random.randint(0, 1) == 0:
return 'Компьютер'
else:
return 'Человек'
def makeMove(board, tile, xstart, ystart):
# Поместить фишку на игровое поле в позицию xstart, ystart и перевернуть какую-либо фишку противника.
# Вернуть False, если это недопустимый ход; вернуть True, если допустимый.
tilesToFlip = isValidMove(board, tile, xstart, ystart)
if tilesToFlip == False:
return False
board[xstart][ystart] = tile
for x, y in tilesToFlip:
board[x][y] = tile
return True
def getBoardCopy(board):
# Сделать копию списка board и вернуть ее.
boardCopy = getNewBoard()
for x in range(WIDTH):
for y in range(HEIGHT):
boardCopy[x][y] = board[x][y]
return boardCopy
def isOnCorner(x, y):
# Вернуть True, если указанная позиция находится в одном из четырех углов.
return (x == 0 or x == WIDTH - 1) and (y == 0 or y == HEIGHT - 1)
def getPlayerMove(board, playerTile):
# Позволить игроку ввести свой ход.
# Вернуть ход в виде [x, y] (или вернуть строки 'подсказка' или 'выход').
DIGITS1TO8 = '1 2 3 4 5 6 7 8'.split()
while True:
print('Укажите ход, текст "выход" для завершения игры или "подсказка" для вывода подсказки.')
move = input().lower()
if move == 'выход' or move == 'подсказка':
return move
if len(move) == 2 and move[0] in DIGITS1TO8 and move[1] in DIGITS1TO8:
x = int(move[0]) - 1
y = int(move[1]) - 1
if isValidMove(board, playerTile, x, y) == False:
continue
else:
break
else:
print('Это недопустимый ход. Введите номер столбца (1-8) и номер ряда (1-8).')
print('К примеру, значение 81 перемещает в верхний правый угол.')
return [x, y]
def getComputerMove(board, computerTile):
# Учитывая данное игровое поле и данную фишку компьютера, определить,
# куда сделать ход, и вернуть этот ход в виде списка [x, y].
possibleMoves = getValidMoves(board, computerTile)
random.shuffle(possibleMoves) # Сделать случайным порядок ходов
# Всегда делать ход в угол, если это возможно.
for x, y in possibleMoves:
if isOnCorner(x, y):
return [x, y]
# Найти ход с наибольшим возможным количеством очков.
bestScore = -1
for x, y in possibleMoves:
boardCopy = getBoardCopy(board)
makeMove(boardCopy, computerTile, x, y)
score = getScoreOfBoard(boardCopy)[computerTile]
if score > bestScore:
bestMove = [x, y]
bestScore = score
return bestMove
def printScore(board, playerTile, computerTile):
scores = getScoreOfBoard(board)
print('Ваш счет: %s. Счет компьютера: %s.' % (scores[playerTile], scores[computerTile]))
def playGame(playerTile, computerTile):
showHints = False
turn = whoGoesFirst()
print(turn + ' ходит первым.')
# Очистить игровое поле и выставить стартовые фишки.
board = getNewBoard()
board[3][3] = 'Х'
board[3][4] = 'О'
board[4][3] = 'О'
board[4][4] = 'Х'
while True:
playerValidMoves = getValidMoves(board, playerTile)
computerValidMoves = getValidMoves(board, computerTile)
if playerValidMoves == [] and computerValidMoves == []:
return board # Ходов нет ни у кого, так что окончить игру.
elif turn == 'Человек': # Ход человека
if playerValidMoves != []:
if showHints:
validMovesBoard = getBoardWithValidMoves(board, playerTile)
drawBoard(validMovesBoard)
else:
drawBoard(board)
printScore(board, playerTile, computerTile)
move = getPlayerMove(board, playerTile)
if move == 'выход':
print('Благодарим за игру!')
sys.exit() # Завершить работу программы.
elif move == 'подсказка':
showHints = not showHints
continue
else:
makeMove(board, playerTile, move[0], move[1])
turn = 'Компьютер'
elif turn == 'Компьютер': # Ход компьютера
if computerValidMoves != []:
drawBoard(board)
printScore(board, playerTile, computerTile)
input('Нажмите клавишу Enter для просмотра хода компьютера.')
move = getComputerMove(board, computerTile)
makeMove(board, computerTile, move[0], move[1])
turn = 'Человек'
print('Приветствуем в игре "Реверси"!')
playerTile, computerTile = enterPlayerTile()
while True:
finalBoard = playGame(playerTile, computerTile)
# Отобразить итоговый счет.
drawBoard(finalBoard)
scores = getScoreOfBoard(finalBoard)
print('X набрал %s очков. O набрал %s очков.' % (scores['Х'], scores['О']))
if scores[playerTile] > scores[computerTile]:
print('Вы победили компьютер, обогнав его на %s очков! Поздравления!' % (scores[playerTile] - scores[computerTile]))
elif scores[playerTile] < scores[computerTile]:
print('Вы проиграли. Компьютер победил вас, обогнав на %s очков.' % (scores[computerTile] - scores[playerTile]))
else:
print('Ничья!')
print('Хотите сыграть еще раз? (да или нет)')
if not input().lower().startswith('д'):
break