Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 27, 2023 07:56:33

AlexxGorr
Зарегистрирован: 2022-11-29
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

Здравствуйте!
помогите разобраться с ошибкой
Traceback (most recent call last):
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 199, in <module>
g.start()
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 110, in start
return self.loop()
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 98, in loop
turn_ai = AI.ask_enter(self.field)
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 188, in ask_enter
intended_value = AI.minimax(board, 0, False)
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 155, in minimax
if game.winner(game.token, board):
File “D_Work/_experience/Python/OOP/TTT_minimax.py”, line 57, in winner
if field[i] == field[i] == field[i] == token_var:
TypeError: ‘int’ object is not subscriptable


ког программы:
https://github.com/AlexxGorr/SkillFactory_AlexxGorr/blob/main/TTT_minimax.py

Офлайн

#2 Янв. 27, 2023 09:02:13

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9727
Репутация: +  843  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

А зачем он игру от доски наследует? И зачем он пользователя от доски наследует?
Доска там максимум сагрегирована должна быть в игре. А пользователь у доски должен операции вызывать, не более того.

Это вот пример, когда изучают не ООП, а “ООП”. Потом будешь говорить, что ООП - это такая ерунда, которая запутывает только всё. А всё дело в том, что учишься просто непонятно у кого. И он тебе типа “преподаёт” типа “ООП”.



Отредактировано py.user.next (Янв. 27, 2023 09:03:37)

Офлайн

#3 Янв. 27, 2023 09:14:19

AlexxGorr
Зарегистрирован: 2022-11-29
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

2 py.user.next
это проблему не решает

Офлайн

#4 Янв. 27, 2023 09:33:20

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9727
Репутация: +  843  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

AlexxGorr
  
intended_value = AI.minimax(board, 0, False)
Вот в этой строке, ты думаешь, что подаёшь?



Офлайн

#5 Янв. 27, 2023 10:09:18

AlexxGorr
Зарегистрирован: 2022-11-29
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

Число

Офлайн

#6 Янв. 27, 2023 10:19:58

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9727
Репутация: +  843  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

Питон подучи сначала.



Офлайн

#7 Янв. 27, 2023 10:22:11

AlexxGorr
Зарегистрирован: 2022-11-29
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

ясно спасибо

Офлайн

#8 Янв. 27, 2023 14:17:19

ivansss
Зарегистрирован: 2023-01-27
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

Мда, думал найду решение, но увы.
Автор отозвись если решил проблему.

Офлайн

#9 Янв. 27, 2023 14:38:43

AlexxGorr
Зарегистрирован: 2022-11-29
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

Нне решил.

Офлайн

#10 Янв. 27, 2023 21:43:51

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9727
Репутация: +  843  -
Профиль   Отправить e-mail  

крестики нолики с ИИ

AlexxGorr
ког программы:
https://github.com/AlexxGorr/SkillFactory_AlexxGorr/blob/main/TTT_minimax.py
from copy import deepcopy
from random import randint
import time
import sys


class Board:
turn_id = 0
busy = []
busy_user = []
busy_ai = []
available = {1: None,
2: None,
3: None,
4: None,
5: None,
6: None,
7: None,
8: None,
9: None}

def __init__(self):
# self.field = list(range(1, 10))
# self.field = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
self.field = [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']

def __str__(self):
res = ''
a = '-' * 17
b = '|'
res += f'{b}{a[:-12]}{b}{a[:-12]}{b}{a[:-12]}{b}'
for i in range(3):
res += f'\n{b} {self.field[0+3*i]} | {self.field[1+3*i]} | {self.field[2+3*i]} {b}'
res += f'\n{b}{a[:-12]}{b}{a[:-12]}{b}{a[:-12]}{b}'
return res


class Game(Board):
turn = randint(1, 5)
Board.turn_id = turn
token = 'XO'
win_situation = ((0, 1, 2),
(3, 4, 5),
(6, 7, 8),
(0, 3, 6),
(1, 4, 7),
(2, 5, 8),
(0, 4, 8),
(2, 4, 6))

def winner(self, token_var, field):
game = Game()
for i in game.win_situation:
if field[i[0]] == field[i[1]] == field[i[2]] == token_var:
return True

def not_win(self):
brd = Board()
if len(brd.busy) >= 9:
return True

def loop(self):
board = Board()
while True:
Board.turn_id += 1

print('busy: ', self.busy)
print('busy_user: ', self.busy_user)
print('busy_ai: ', self.busy_ai)
print('available: ', self.available)
print('field: ', board.field)

if self.winner(self.token[0], board.field):
print('User выиграл!')
break

if self.winner(self.token[1], board.field):
print('AI выиграл!')
break

if Game.not_win(self.field):
print('Ничья')
break

if Board.turn_id % 2 == 0:
print('Ходит User')
turn_user = User.ask_enter(self.field)
board.field[turn_user] = self.token[0]
print(board)
print()

if Board.turn_id % 2 == 1:
print('Ходит AI')
time.sleep(randint(1, 3))
turn_ai = AI.ask_enter(self.field)
board.field[turn_ai-1] = self.token[1]
print(board)
print()

for num, i in enumerate(board.field):
if i == 'X':
self.available.update({num+1: i})
if i == 'O':
self.available.update({num+1: i})

def start(self):
return self.loop()


class User(Board):
def ask_enter(self):
while True:
enter = input('Enter: ')
if ' ' in enter:
print('Не корректный ввод')
continue
if enter.isalpha():
print('Нужна цифра')
continue
if len(enter) > 1:
print('Нужна одна цифра')
continue
if int(enter) < 1:
print('Диапозон ввода от 1 до 9')
continue
if int(enter) in Board.busy:
print('Ячейка занята')
continue
enter_id = int(enter) - 1
Board.busy.append(enter_id+1)
Board.busy_user.append(enter_id+1)
return enter_id


class AI(Board):
# def ask_enter(self):
# board = Board()
# while True:
# enter = randint(1, 9)
# if enter not in board.busy:
# board.busy.append(enter)
# board.busy_ai.append(enter)
# return enter
# else:
# print(f'Ячейка занята: {enter}')
# continue

def minimax(self, board, depth, is_maximizing=None):
# sys.setrecursionlimit(50)
game = Game()
brd = Board()
if game.winner(game.token[0], board):
return 100
if game.winner(game.token[1], board):
return -100
if Game.not_win(brd.field):
return 0
if is_maximizing:
best_value = -sys.maxsize
for key in range(1, 10):
if key not in brd.busy:
board[key] = game.token[1]
intended_value = AI.minimax(board, depth + 1, False)
board[key] = ' '
best_value = max(best_value, intended_value)
else:
best_value = sys.maxsize
for key in range(1, 10):
if key not in brd.busy:
board[key] = game.token[0]
intended_value = AI.minimax(board, depth + 1, True)
board[key] = ' '
best_value = min(best_value, intended_value)
return best_value

def ask_enter(self):
brd = Board()
game = Game()
enter = None
best_value = -sys.maxsize
board = [deepcopy(i) for i in brd.field]
for key in range(1, 10):
if key not in brd.busy:
board[key] = game.token[1]
intended_value = AI.minimax(board, 0, False)
board[key] = ' '
if intended_value > best_value:
best_value = intended_value
enter = key
brd.busy.append(enter)
brd.busy_ai.append(enter)
return enter


g = Game()
g.start()
Вот этот код, чтобы было понятно, о чём идёт речь.

Вот пример, который показывает разницу между вызовом метода экземпляра класса и вызовом метода самого класса
  
>>> class A:
...     
...     def method(self, arg):
...         return arg * 2
... 
>>> a = A()
>>> 
>>> a.method(2)
4
>>> A.method(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: method() missing 1 required positional argument: 'arg'
>>> 
>>> A.method(None, 3)
6
>>>
Соответственно, метод у класса можно вызывать, но нужно помнить, что там есть первый аргумент self, который никуда не делся.

Вот пример, который показывает, как можно сделать метод, который хранится в классе просто
  
>>> class A:
...     
...     @staticmethod
...     def method(arg):
...         return arg * 2
... 
>>> a = A()
>>> 
>>> a.method(2)
4
>>> A.method(3)
6
>>>
В таком методе self не используется. При этом такой метод можно вызывать у экземпляра класса и вызывать просто у класса одинаково.

То есть это у тебя в коде проявляется незнание питона и того, как он устроен, как в нём что работает, как в нём что вызывается и как эти аргументы присваиваются в вызовах.

Что касается ООП.

Отношение наследования обязательно подразумевает под собой отношение “одно является другим” и никак иначе.

Есть, например, фрукт, яблоко, зелёное яблоко и красное яблоко. Вот яблоко - это фрукт. Зелёное яблоко - это яблоко. Красное яблоко - это яблоко. Красное яблоко, например, зелёным яблоком не является. Но при этом красное яблоко является яблоком, а так как яблоко является фруктом, то красное яблоко является фруктом. С зелёным яблоком то же самое происходит. Зелёное яблоко не является красным яблоком. Но зелёное яблоко является яблоком, а так как яблоко является фруктом, то зелёное яблоко является фруктом.

Получается, что есть фрукт, от него происходит яблоко, а от яблока происходит зелёное яблоко и происходит красное яблоко.
              Фрукт
|
Яблоко
|
------------------------
| |
Зелёное яблоко Красное яблоко
Соответственно, если у яблока определить метод “нарисовать на экране в раскрашенном виде”, то у зёленого яблока этот метод появится и будет рисовать зелёное яблоко зелёным, а у красного яблока этот метод появится и будет рисовать красное яблоко красным. То есть метод будет только в одном месте записан, но появится при этом везде, и везде он будет работать абсолютно по разному. Это то, для чего нужно ООП, - чтобы с помощью наследования сокращать пишущийся код до каких-то мелких записей и устраивать вот такой полиморфизм методов при этом, чтобы маленькая запись делала много изменений в коде сразу, одним махом.

При этом, если какой-то метод определить у фрукта, то этот метод пойдёт не только во все яблоки, но и во все груши, во все ананасы, во все бананы, которые там появятся в будущем, когда тебе заказчик скажет “а мне ещё груши нужны теперь, добавь их в программу”. То есть тебе надо будет добавить в программу совсем немного кода, при этом он весь будет работать уже, потому что всё уже написано заранее и прорастает через наследование само собой.

Вот это то, для чего нужно ООП.

При этом твой код к ООП, где доска равна игра, а игра равна доска, а лопата равна балалайка, не имеет к ООП никакого отношения. И знание или незнание питона тут тоже ни при чём. ООП - это отдельная тема; изучение питона, даже полностью, никак не поможет тебе ООП узнать. ООП надо изучать отдельно от всех языков программирования, потому что это отдельная теория.


tags: oop theory



Отредактировано py.user.next (Янв. 27, 2023 21:59:11)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version