Я только что закончил работу над ИИ для крестиков-ноликов и был бы очень благодарен за мнения и комментарии по этому проекту. Я хотел бы добавить его в свой «портфель разработчиков Python начального уровня».
ПРОЧТИ МЕНЯ:
Простой ИИ, играющий сам с собой в крестики-нолики. Вначале ходы выбираются случайным образом, каждый возможный ход имеет одинаковую вероятность разыгрывания. Последовательность ходов, которая приводит к победе, набирает очки, поэтому в будущих играх будет больше шансов выбрать этот ход. Соответственно ходы, закончившиеся в проигрышном состоянии, будут выбираться реже. Примерно после 200 000 игр будет более 99% ничьих — оба игрока не сделают ни одной ошибки в более чем 99% игр.
Основной класс:
import rules
#main game loop. Number of repetition defines how many games are played
for i in range (1):
#these two lists are used to store moves used in each game
moves_X = []
moves_O = []
#creation of an empty board, flags move_X and move_O are used to define whether it is Xs or Os move at the moment
board = [{'number': 100000, 'board': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 'value': 100}]
move_X = True
move_O = False
#change flag is the cap that prevents the game to be played for longher than 9 moves
change = 0
#this loop goes on until Os or Xs wins or it is a draw
while True:
if move_X and change <= 4:
#to define new board after Xs move we use function called draw() defined in the rules module
board = rules.draw(0, change, board)
moves_X.append(board)
#to visualize the game we use draw_board() function defined in rules module
print(rules.draw_board(board))
move_X = False
move_O = True
#using iswin function from rules() we check if Xs have alredy won
if (rules.iswin(board[0]['board'], 'X')):
print(rules.draw_board(board))
print('X won!')
#if Xs won we add points to all of Xs moves from that game
#and take points from Os moves
for move in moves_X:
move[0]['value'] += 1
for move in moves_O:
if move[0]['value'] > 1:
move[0]['value'] -= 1
break
#next O play its move
elif move_O and change<4:
board = rules.draw(1, change, board)
print(rules.draw_board(board))
moves_O.append(board)
move_X = True
move_O = False
change += 1
if (rules.iswin(board[0]['board'], 'O')):
print(rules.draw_board(board))
print('O won!')
for move in moves_O:
move[0]['value'] += 1
for move in moves_X:
if move[0]['value'] > 1:
move[0]['value'] -= 1
break
#if the board is full and neither of the players won
else:
print('Draw!')
break
#after compliton of the main game loop we save the results
rules.save()
all_data Класс:
import itertools
#used to create list of all combinations of ' ', X and O. Each combination have its number and value
#that list will be filtered and sorted in the data_base module
def board_init():
move_number = []
for b,i in enumerate(itertools.product(' XO', repeat=9)):
if b==100000:
break
else:
move_n_number = {'number': b, 'board': i, 'value': 100}
move_number.append(move_n_number)
return move_number
data_base Класс:
import all_data
import json
#board_sort module sorts and filters list created with board_init() in the all_data module
def board_sort(move_n):
#move_list_X and move_list_O are used to sort moves by sign and number, from first to fifth in Xs and fourth in Os.
move_list_X=[[], [], [], [], []]
move_list_O=[[], [], [], []]
move_list = (move_list_X, move_list_O)
for i in move_n:
if i.get('board').count('X')==1 and i.get('board').count('O')==0:
move_list_X[0].append(i)
elif i.get('board').count('X')==1 and i.get('board').count('O')==1:
move_list_O[0].append(i)
elif i.get('board').count('X')==2 and i.get('board').count('O')==1:
move_list_X[1].append(i)
elif i.get('board').count('X')==2 and i.get('board').count('O')==2:
move_list_O[1].append(i)
elif i.get('board').count('X')==3 and i.get('board').count('O')==2:
move_list_X[2].append(i)
elif i.get('board').count('X')==3 and i.get('board').count('O')==3:
move_list_O[2].append(i)
elif i.get('board').count('X')==4 and i.get('board').count('O')==3:
move_list_X[3].append(i)
elif i.get('board').count('X')==4 and i.get('board').count('O')==4:
move_list_O[3].append(i)
elif i.get('board').count('X')==5 and i.get('board').count('O')==4:
move_list_X[4].append(i)
else:
continue
return move_list
def save(move_list):
with open('all_moves.txt', 'w') as f:
json.dump(move_list, f)
правила Класс:
import random
import json
import all_data
import data_base
#if there is no file 'all_moves.txt' it is is created
try:
with open('all_moves.txt') as json_file:
move_list = json.load(json_file)
except IOError:
move_n = all_data.board_init()
move_list = data_base.board_sort(move_n)
#iswin function is used to check if Xs or Os have alredy won
def iswin(board, letter="X"):
if board[0]==letter and board[1]==letter and board[2]==letter:
return True
elif board[3]==letter and board[4]==letter and board[5]==letter:
return True
elif board[6] == letter and board[7] == letter and board[8] == letter:
return True
elif board[0] == letter and board[3] == letter and board[6] == letter:
return True
elif board[1] == letter and board[4] == letter and board[7] == letter:
return True
elif board[2] == letter and board[5] == letter and board[8] == letter:
return True
elif board[0] == letter and board[4] == letter and board[8] == letter:
return True
elif board[6] == letter and board[4] == letter and board[2] == letter:
return True
else:
return False
#draw function is used to draw a move from a list of possible moves
#the probability of each choice is dependent on previous results
def draw(letter, number, board):
possible_moves=[]
move = move_list[letter][number]
for i in move:
sum=0
for z, g in zip(i['board'], board[0]['board']):
if z==g:
continue
else:
sum += 1
if sum==1:
possible_moves.append(i)
else:
continue
return(random.choices(possible_moves, weights=[i['value'] for i in possible_moves], k = 1))
#saves changes made in the 'all_moves.txt' file
def save():
with open('all_moves.txt', 'w') as f:
json.dump(move_list, f)
#function used to visualize present state of the board
def draw_board(board):
return(
'''
{}
{}
{}
'''.format(board[0]['board'][:3], board[0]['board'][3:6], board[0]['board'][6:])
)
Ваше здоровье!