pythonでオセロ（人vsコンピュータ）作ってみた

前回のオセロから、マスごとに評価値を設定して、コンピュータが置けるなかで一番評価値が高いマスに置く、というプログラムを作りました。
もちろん激ヨワです。オセロ苦手な自分でも勝てます。ここから、評価値に「置いたとき相手が置ける場所の数」「相手に囲まれているマス」などを重み付けして足すことで、強くしていきます。

予定は、
①自分で重み調整
②AIにパラメータとして与えて重み調整←やっとAI！！！
③何手か先まで予測させて、ミニマックス法かαβ法
④何手か先まで予測を前提として、AIを使って重み調整

楽しみです。９月中には完成させたい。

↓ソースコード
```python:オセロ（人vsコンピュータ）
import tkinter
from tkinter import *

class player:
    def __init__(self):
        self.name="name"
        self.disc=0
                
player1=player()
player2=player()
player1.name="aaa"
player1.disc=1
player2.name="bbb"
player2.disc=2

can_place=[]
cnt_can=4
place_value=[ 70,-20, 60, -10, -10, 60,-20, 70,
             -20,-60,-30, -5, -5,-30,-60,-20,
              60,-30, 25,  10,  10, 25,-30, 60,
              -10, -5,  10,-25,-25,  10, -5, -10,
              -10, -5,  10,-25,-25,  10, -5, -10,
              60,-30, 25,  10,  10, 25,-30, 60,
             -20,-60,-30, -5, -5,-30,-60,-20,
              70,-20, 60, -10, -10, 60,-20, 70]
cnt_cannot=0
com_place=19

for i in range(0,64):
    if i==19 or i==26 or i==37 or i==44:
        can_place.append(3)
    else:
        can_place.append(0)

#ボードの初期化
board=[]#壁も含めた盤面
Re_board=[]#壁をのぞいた盤面
for i in range(0,100):
    if (0<=i and i<=9) or (90<=i and i<=99) or i%10==0 or i%10==9:
        board.append(5)
    elif i==44 or i==55:
        board.append(2)
        Re_board.append(i)
    elif i==45 or i==54:
        board.append(1)
        Re_board.append(i)
    else:
        board.append(0)
        Re_board.append(i)

class Application(tkinter.Frame):
    def __init__(self,win=None):
        super().__init__(win,width=680,height=480,borderwidth=1,relief='groove')
        self.win=win
        self.pack()
        self.pack_propagate(0)
        self.create_widgets()
        self.create_button(board,can_place)
        
    def create_widgets(self):
        self.label_turn=Label(self,text="あなたが先攻です\n黒を置いてください",font=("MSゴシック", "15"),justify="left")
        self.label_turn.place(x=500,y=50)
        self.label_cnt1=Label(self,text="黒:2枚",font=("MSゴシック", "20"))
        self.label_cnt1.place(x=500,y=120)
        self.label_cnt2=Label(self,text="白:2枚",font=("MSゴシック", "20"))
        self.label_cnt2.place(x=500,y=160)
        self.label_win=Label(self,text="",font=("MSゴシック", "15"),justify="left")
        self.button_com=Button(self,text="決定",font=("MSゴシック", "20"),command=self.com_run)
        self.button_com.place(x=500,y=250)
        self.button_com.configure(bg="yellow")
       
    def create_button(self,board,can_place):
        self.button=[]
        for i in range(0,8):
            for j in range(0,8):
                if board[(i+1)*10+j+1]==2:
                    self.button.append(Button(self,text="●",font=("MSゴシック","45"),fg="white",command=self.btn_clicked(self.button,i*8+j)))
                elif board[(i+1)*10+j+1]==1:
                    self.button.append(Button(self,text="●",font=("MSゴシック","45"),command=self.btn_clicked(self.button,i*8+j)))
                elif can_place[i*8+j]==3:
                    self.button.append(Button(self,text="●",font=("MSゴシック","20"),fg="yellow",command=self.btn_clicked(self.button,i*8+j)))
                else:
                    self.button.append(Button(self,command=self.btn_clicked(self.button,i*8+j)))
                self.button[i*8+j].place(x=j*60,y=i*60,width=60,height=60,)
                self.button[i*8+j].configure(bg="green")
    
    def btn_clicked(self,button,place):
        def inner():
            def show_board(board,button,can_place,player,finish):#盤面をウィンドウに表示
                if player==player1:
                    self.label_turn["text"]="「決定」を\n押してください"
                else:
                    self.label_turn["text"]="あなたの番です"
                cnt1,cnt2=cnt_disc(board)
                self.label_cnt1["text"]="黒:"+str(cnt1)+"枚"
                self.label_cnt2["text"]="白:"+str(cnt2)+"枚"
                if (cnt1+cnt2==64) or (cnt1==0) or (cnt2==0) or finish==True:
                    self.label_turn["text"]=""
                    if cnt1>cnt2:
                        self.label_win["text"]=f'あなたの勝利です'
                        self.label_win.place(x=500,y=200)
                    elif cnt1<cnt2:
                        self.label_win["text"]=f'コンピュータの勝利です'
                        self.label_win.place(x=500,y=200)
                    else:
                        self.label_win["text"]="引き分けです"
                        self.label_win.place(x=500,y=200)
                else:
                    pass
                for i in range(0,8):
                    for j in range(0,8):
                        button[i*8+j].destroy()
                        
                self.create_button(board,can_place)
                for i in range(0,8):
                    for j in range(0,8):
                        button[i*8+j].place(x=j*60,y=i*60,width=60,height=60,)
                        button[i*8+j].configure(bg="green")
                
            def reverse(place_a,board,player):#裏返す関数、戻り値→裏返せる枚数
                dir=(-11,-10,-9,-1,1,9,10,11)#方向ベクトル
                sum_cnt_rev=0#そこに置いたときに裏返せる枚数
                for i in dir:
                    tmp_place=place_a#placeの初期化
                    cnt_rev=0#その方向においての裏返せる枚数
                    while board[tmp_place+i]!=player.disc:
                        if board[tmp_place+i]==(int(player.disc)-1.5)*-1+1.5:#ディスクが１なら２，２なら１（相手のディスクがある）
                            tmp_place+=i
                            cnt_rev+=1
                        else:#0（空きマス）か5（壁）
                            cnt_rev=0
                            break
                    for j in range(1,cnt_rev+1):
                        board[place_a+j*i]=player.disc
                    sum_cnt_rev+=cnt_rev
                return sum_cnt_rev
            
            def check(player,board,Re_board):#まだ置ける場所があるかチェックする関数,戻り値→置ける場所の数、座標
                dir=(-11,-10,-9,-1,1,9,10,11)#方向ベクトル
                cnt_can=0#置ける場所の数
                can_place=[]
                for place in Re_board:
                    sum_cnt_rev=0#そこに置いたときに裏返せる枚数
                    if board[place]==0:
                        for i in dir:
                            tmp_place=place#placeの初期化
                            cnt_rev=0#その方向においての裏返せる枚数
                            while board[tmp_place+i]!=player.disc:
                                if board[tmp_place+i]==(int(player.disc)-1.5)*-1+1.5:#ディスクが１なら２，２なら１（相手のディスクがある）
                                    tmp_place+=i
                                    cnt_rev+=1
                                else:#0（空きマス）か5（壁）
                                    cnt_rev=0
                                    break
                            sum_cnt_rev+=cnt_rev
                    else:
                        pass
                    if sum_cnt_rev!=0:
                        cnt_can+=1
                        can_place.append(place)
                    else:
                        pass
                return (cnt_can,can_place)

            def run(player,board):#実行する関数,戻り値→実行ok:1、実行no:0
                #石を置く
                
                a=int(place)
                place_a=(a//8+1)*10+(a%8+1)
                #裏返す
                sum_cnt_rev=reverse(place_a,board,player)
                if sum_cnt_rev==0 or board[place_a]!=0:
                    return 0
                else:
                    board[place_a]=int(player.disc)
                    return 1
            
            def cnt_disc(board):
                cnt1=0
                cnt2=0
                for i in Re_board:
                    if board[i]==1:
                        cnt1+=1
                    elif board[i]==2:
                        cnt2+=1
                    else:
                        pass
                return (cnt1,cnt2)
            
            def decide_place(can_place):#コンピュータの置く場所を決定
                global com_place
                tmp_max=-100
                max_value=-100
                for i in range(0,len(can_place)):
                    tmp_max=place_value[can_place[i]]
                    if tmp_max>max_value:
                        max_value=tmp_max
                        com_place=can_place[i]
                    else:
                        pass
                
            can_place=[]
            finish=False
            global cnt_can
            global cnt_cannot
            self.label_win["text"]=""
                #１の番
            if cnt_can!=0:#置ける
                run_can=run(player1,board)
                cnt_can,tmp_can_place=check(player2,board,Re_board)
                for i in range(0,len(tmp_can_place)):
                    tmp_can_place[i]=(tmp_can_place[i]//10-1)*8+tmp_can_place[i]%10-1
                decide_place(tmp_can_place)
                cnt=0
                for i in range(0,8):
                    for j in range(0,8):
                        for r in range(0,len(tmp_can_place)):
                            if tmp_can_place[r]==i*8+j:
                                cnt+=1
                            else:
                                pass
                        if cnt!=0:
                            can_place.append(3)
                        else:
                            can_place.append(0)
                        cnt=0 
                cnt_cannot=0
                if run_can==1:
                    show_board(board,button,can_place,player1,finish)
                else:
                    pass
            else:#置けない
                run_can=1
                cnt_can=1
                if cnt_cannot==1:#相手も置けなかった
                    finish=True
                    show_board(board,button,can_place,player1,finish)
                else:
                    self.label_win["text"]="黒をどこにも置けません\n「決定」を押してください"
                    self.label_win.place(x=500,y=200)
                cnt_cannot+=1
            
        return inner
    
    def com_run(self):
        def show_board(board,can_place,finish):#盤面をウィンドウに表示
            self.label_turn["text"]="あなたの番です"
            cnt1,cnt2=cnt_disc(board)
            self.label_cnt1["text"]="黒:"+str(cnt1)+"枚"
            self.label_cnt2["text"]="白:"+str(cnt2)+"枚"
            if (cnt1+cnt2==64) or (cnt1==0) or (cnt2==0) or finish==True:
                self.label_turn["text"]=""
                if cnt1>cnt2:
                    self.label_win["text"]=f'黒の勝利です'
                    self.label_win.place(x=500,y=200)
                elif cnt1<cnt2:
                    self.label_win["text"]=f'白の勝利です'
                    self.label_win.place(x=500,y=200)
                else:
                    self.label_win["text"]="引き分けです"
                    self.label_win.place(x=500,y=200)
            else:
                pass
            for i in range(0,8):
                for j in range(0,8):
                    self.button[i*8+j].destroy()
                    
            self.create_button(board,can_place)
            for i in range(0,8):
                for j in range(0,8):
                    self.button[i*8+j].place(x=j*60,y=i*60,width=60,height=60,)
                    self.button[i*8+j].configure(bg="green")
            
        def reverse(place_a,board,player):#裏返す関数、戻り値→裏返せる枚数
            dir=(-11,-10,-9,-1,1,9,10,11)#方向ベクトル
            sum_cnt_rev=0#そこに置いたときに裏返せる枚数
            for i in dir:
                tmp_place=place_a#placeの初期化
                cnt_rev=0#その方向においての裏返せる枚数
                while board[tmp_place+i]!=player.disc:
                    if board[tmp_place+i]==(int(player.disc)-1.5)*-1+1.5:#ディスクが１なら２，２なら１（相手のディスクがある）
                        tmp_place+=i
                        cnt_rev+=1
                    else:#0（空きマス）か5（壁）
                        cnt_rev=0
                        break
                for j in range(1,cnt_rev+1):
                    board[place_a+j*i]=player.disc
                sum_cnt_rev+=cnt_rev
            return sum_cnt_rev
        
        def check(player,board,Re_board):#まだ置ける場所があるかチェックする関数,戻り値→置ける場所の数、座標
            dir=(-11,-10,-9,-1,1,9,10,11)#方向ベクトル
            cnt_can=0#置ける場所の数
            can_place=[]
            for place in Re_board:
                sum_cnt_rev=0#そこに置いたときに裏返せる枚数
                if board[place]==0:
                    for i in dir:
                        tmp_place=place#placeの初期化
                        cnt_rev=0#その方向においての裏返せる枚数
                        while board[tmp_place+i]!=player.disc:
                            if board[tmp_place+i]==(int(player.disc)-1.5)*-1+1.5:#ディスクが１なら２，２なら１（相手のディスクがある）
                                tmp_place+=i
                                cnt_rev+=1
                            else:#0（空きマス）か5（壁）
                                cnt_rev=0
                                break
                        sum_cnt_rev+=cnt_rev
                else:
                    pass
                if sum_cnt_rev!=0:
                    cnt_can+=1
                    can_place.append(place)
                else:
                    pass
            return (cnt_can,can_place)
        
        def run(player,board):#実行する関数,戻り値→実行ok:1、実行no:0
            #場所を決めて、石を置く
            a=com_place
            
            place_a=(a//8+1)*10+(a%8+1)
            #裏返す
            sum_cnt_rev=reverse(place_a,board,player)
            if sum_cnt_rev==0 or board[place_a]!=0:
                return 0
            else:
                board[place_a]=int(player.disc)
                return 1
        
        def cnt_disc(board):
            cnt1=0
            cnt2=0
            for i in Re_board:
                if board[i]==1:
                    cnt1+=1
                elif board[i]==2:
                    cnt2+=1
                else:
                    pass
            return (cnt1,cnt2)
            
        can_place=[]
        finish=False
        global cnt_can
        global cnt_cannot
        self.label_win.pack_forget()
            #１の番
        if cnt_can!=0:#置けた場合
            run_can=run(player2,board)
            cnt_can,tmp_can_place=check(player1,board,Re_board)
            for i in range(0,len(tmp_can_place)):
                tmp_can_place[i]=(tmp_can_place[i]//10-1)*8+tmp_can_place[i]%10-1
            cnt=0
            for i in range(0,8):
                for j in range(0,8):
                    for r in range(0,len(tmp_can_place)):
                        if tmp_can_place[r]==i*8+j:
                            cnt+=1
                        else:
                            pass
                    if cnt!=0:
                        can_place.append(3)
                    else:
                        can_place.append(0)
                    cnt=0 
            if run_can==1:
                show_board(board,can_place,finish)
            else:
                pass
        else:
            run_can=1
            cnt_can=1
            if cnt_cannot==1:#相手も置けなかった
                finish=True
                show_board(board,can_place,finish)
            else:
                self.label_win["text"]="コンピュータは\nどこにも置けません"
                self.label_win.place(x=500,y=200)
                self.label_turn["text"]="あなたの番です"
            cnt_cannot+=1
            
win=Tk()
win.title("オセロ")
win.geometry('700x500')
app=Application(win=win)
app.mainloop()
```