Files
pythonCoolGames/reversi/computerVScomputer/AISim1.py
BarsTigerMeowcat b01c9d869f Initial commit
2020-01-26 12:46:16 +02:00

243 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# "Реверси": клон "Отелло".
import random
import sys
WIDTH = 8 # Игровое поле содержит 8 клеток по ширине.
HEIGHT = 8 # Игровое поле содержит 8 клеток по высоте.
CONST_X = 'X'
CONST_O = 'O'
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 == CONST_X:
otherTile = CONST_O
else:
otherTile = CONST_X
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):
# Определить количество очков, подсчитав фишки. Вернуть словарь с ключами CONST_X и CONST_O.
xscore = 0
oscore = 0
for x in range(WIDTH):
for y in range(HEIGHT):
if board[x][y] == CONST_X:
xscore += 1
if board[x][y] == CONST_O:
oscore += 1
return {CONST_X:xscore, CONST_O:oscore}
def enterPlayerTile():
# Позволить игроку ввести выбранную фишку.
# Возвращает список с фишкой игрока в качестве первого элемента и фишкой компьютера в качестве второго.
tile = ''
while not (tile == CONST_X or tile == CONST_O):
print('Вы играете за Х или О?')
tile = input().upper()
# Первый элемент в списке — фишка игрока, второй элемент — фишка компьютера.
if tile == CONST_X:
return [CONST_X, CONST_O]
else:
return [CONST_O, CONST_X]
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] = CONST_X
board[3][4] = CONST_O
board[4][3] = CONST_O
board[4][4] = CONST_X
while True:
playerValidMoves = getValidMoves(board, playerTile)
computerValidMoves = getValidMoves(board, computerTile)
if playerValidMoves == [] and computerValidMoves == []:
return board # Ходов нет ни у кого, так что окончить игру.
elif turn == 'Человек': # Ход человека
if playerValidMoves != []:
move = getComputerMove(board, playerTile)
makeMove(board, playerTile, move[0], move[1])
turn = 'Компьютер'
elif turn == 'Компьютер': # Ход компьютера
if computerValidMoves != []:
move = getComputerMove(board, computerTile)
makeMove(board, computerTile, move[0], move[1])
turn = 'Человек'
print('Приветствуем в игре "Р е в е р с и"!')
playerTile, computerTile = [CONST_X, CONST_O]
while True:
finalBoard = playGame(playerTile, computerTile)
# Отобразить итоговый счет.
drawBoard(finalBoard)
scores = getScoreOfBoard(finalBoard)
print('X набрал %s очков. O набрал %s очков.' % (scores[CONST_X], scores[CONST_O]))
if scores[playerTile] > scores[computerTile]:
print('ИИ 1 победил ИИ 2, обогнав его на %s очков!' % (scores[playerTile] - scores[computerTile]))
elif scores[playerTile] < scores[computerTile]:
print('ИИ 2 победил ИИ 1, обогнав его на %s очков!' % (scores[computerTile] - scores[playerTile]))
else:
print('Ничья!')
print('Хотите сыграть еще раз? (да или нет)')
if not input().lower().startswith('д'):
break