LoginSignup
0
0

pythonでオセロ(人vs人)作ってみた

Posted at

前回print関数で画面表示するシステムだけのオセロを作ったので、Tkinterでウィンドウからクリックで遊べるように実装しました。

ボタンウィジェットが64個と多いのでリストに格納しながら一気に作ったのですが、そこからクリックされた特定のボタンからのみ関数を呼び出すのにとても苦しみました。for文のiを一緒に関数の引数に送ってあげるだけで解決。ちくしょう

今、マスごとに値を設定して、コンピュータが静的に手を評価して置くようなものをつくっています。多分この次に念願のオセロAI。楽しみすぎる。

↓ソースコード、多分めちゃくちゃ汚いです

オセロ(人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

turn=0
can_place=[]
cnt_can=4
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="黒が先攻です",font=("MSゴシック", "20"))
       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ゴシック", "10"))
       
    def create_button(self,board,can_place):
        button=[]
        for i in range(0,8):
            for j in range(0,8):
                if board[(i+1)*10+j+1]==2:
                    button.append(Button(self,text="",font=("MSゴシック","45"),fg="white",command=self.btn_clicked(button,i*8+j)))
                elif board[(i+1)*10+j+1]==1:
                    button.append(Button(self,text="",font=("MSゴシック","45"),command=self.btn_clicked(button,i*8+j)))
                elif can_place[i*8+j]==3:
                    button.append(Button(self,text="",font=("MSゴシック","20"),fg="yellow",command=self.btn_clicked(button,i*8+j)))
                else:
                    button.append(Button(self,command=self.btn_clicked(button,i*8+j)))
                button[i*8+j].place(x=j*60,y=i*60,width=60,height=60,)
                button[i*8+j].configure(bg="green")
    
    def btn_clicked(self,button,place):
        def inner():
            def show_board(board,button,can_place,player):#盤面をウィンドウに表示
                if player==player1:
                    self.label_turn["text"]="白の番です"
                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):
                    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:#ディスクが1なら2,2なら1(相手のディスクがある)
                            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:#ディスクが1なら2,2なら1(相手のディスクがある)
                                    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)
                
            can_place=[]
            global turn
            global cnt_can
            self.label_win.pack_forget()
            if turn%2==0:
                #1の番
                if cnt_can!=0:
                    run_can=run(player1,board)
                    turn+=run_can
                    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
                    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,button,can_place,player1)
                    else:
                        pass
                else:
                    run_can=1
                    self.label_win["text"]="黒をどこにも置けませんでした"
                    self.label_win.place(x=500,y=200)
                    turn+=run_can
                    cnt_can=1
            else:
                #2の番
                if cnt_can!=0:
                    run_can=run(player2,board)
                    turn+=run_can
                    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,button,can_place,player2)
                    else:
                        pass
                else:
                    run_can=1
                    self.label_win["text"]="白をどこにも置けませんでした"
                    self.label_win.place(x=500,y=200)
                    turn+=run_can
                    cnt_can=1
        return inner
    
win=Tk()
win.title("オセロ")
win.geometry('700x500')
app=Application(win=win)
app.mainloop()

もうすぐ大学が始まってしまう。夏にほとんど勉強できなかった。焦りがすごい。
でもこの夏で3か月分くらいの生活費稼げたし、後期はバイトちょっと減らしてもっと勉強する時間増やします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0