pythonでオセロ(8×8)を作る方法 応用編のコード

このページでは「pythondeでオセロ(8×8)を作る方法 応用編」のコードを載せています。

アルゴリズムや解説を読みたい人はこちらから

 

pythonのコード

""" othello16-pygame.py  Copyright 2019 niwakoma """
import numpy as np
import random
import copy
import pygame
from pygame.locals import QUIT, MOUSEBUTTONDOWN
import sys
from math import floor


pygame.init() # pygameを初期化
global SURFACE
SURFACE = pygame.display.set_mode((1000, 600)) # windowのサイズを設定
global FPSCLOCK
FPSCLOCK = pygame.time.Clock()


def stone_location(stone):
    stone_list =[]
    tuple_list = np.where(field == stone)
    for i in range(len(tuple_list[0])):
        stone_list.append((tuple_list[0][i], tuple_list[1][i]))
    return stone_list

def empty_location(stone_list):
    emp = {}
    for x, y in stone_list:
        for i, j in offset:
            p = (x+i, y+j)
            if((p[0] <= 7) and (p[0] >= 0) and (p[1] <= 7) and (p[1] >= 0) ):
                if((field[p] == EMPTY) and not(p in emp)):
                    emp[p] = []
                    emp[p].append((i, j))
                elif((field[p] == EMPTY) and (p in emp)):
                    emp[p].append((i, j))
                else:
                    pass
            else:
                pass
    return emp

def bw_turn(TURN):
    stone_list = stone_location(3 - TURN)
    emp = empty_location(stone_list)
    stone_possible = []
    stone_dic = {}
    for kx, ky in emp.keys():
        for vx, vy in emp[kx, ky]:
            addx = vx*(-1)
            addy = vy*(-1)
            px = kx+(vx*(-1))
            py = ky+(vy*(-1))
            p = (px, py)
            while((px >=0 and px <= 7) and (py >= 0 and py <= 7)):
                if(field[p] == (3 - TURN)):
                    pass
                elif(field[p] == TURN):
                    if(not((kx, ky) in stone_dic) and not((kx, ky) in stone_possible)):
                        stone_possible.append((kx, ky))
                        stone_dic[(kx, ky)] = [(addx, addy)]
                    elif(((kx, ky) in stone_dic) and ((kx, ky) in stone_possible)):
                        stone_dic[(kx, ky)].append((addx, addy))
                    break
                else:
                    break
                px = px + addx
                py = py + addy
                p = (px, py)
    # black_possibleから1つ選出する
    if(len(stone_possible) == 0):
        return (-1, -1), [(0, 0)]
    r = random.randrange(len(stone_possible))
    return stone_possible[r], stone_dic[stone_possible[r]]

def update_field(TURN, point, offset_list):
    px = point[0]
    py = point[1]
    update_possible = []
    update_possible.append(point)
    for addx, addy in offset_list:
        vx = px
        vy = py
        value = point
        while((vx >=0 and vx <= 8) and (vy >= 0 and vy <= 8)):
            p = field[value]
            if((p == TURN) or (p == EMPTY) and not(value in update_possible)):
                break
            elif((p != TURN) and (p != EMPTY) and not(value in update_possible)):
                update_possible.append(value)
            else:
                pass
            vx = vx + addx
            vy = vy + addy
            value = (vx, vy)
    for i in update_possible:
        field[i] = TURN
    return field

def address2point(address):
    for i in range(8):
        for j in range(8):
            if(field_address[(i, j)] == address and field[(i, j)] == 0):
                return (i, j)
    return (-1, -1)

def point2offset(point, TURN):
    px = point[0]
    py = point[1]
    p2o_list = []
    for i, j in offset:
        vx = px + i
        vy = py + j
        p = (vx, vy)
        if((p[0] <= 7) and (p[0] >= 0) and (p[1] <= 7) and (p[1] >= 0) and (field[p] != TURN) and (field[p] != EMPTY)):
            vx = vx + i
            vy = vy + j
            p = (vx, vy)
            while((p[0] <= 7) and (p[0] >= 0) and (p[1] <= 7) and (p[1] >= 0)):
                if(field[p] != TURN and field[p] != EMPTY):
                    pass
                elif(field[p] == TURN and field[p] != EMPTY):
                    p2o_list.append((i, j))
                    break
                elif(field[p] != TURN and field[p] == EMPTY):
                    break
                vx = vx + i
                vy = vy + j
                p = (vx, vy)
    return p2o_list

def address_check(point, TURN):
    bw_stone = stone_location(3-TURN)
    emp = empty_location(bw_stone)
    stone_possible = []
    stone_dic = {}
    for kx, ky in emp.keys():
        for vx, vy in emp[kx, ky]:
            addx = vx*(-1)
            addy = vy*(-1)
            px = kx+(vx*(-1))
            py = ky+(vy*(-1))
            p = (px, py)
            while((px >=0 and px <= 7) and (py >= 0 and py <= 7)):
                if(field[p] != TURN):
                    pass
                elif(field[p] == TURN):
                    if(not((kx, ky) in stone_dic) and not((kx, ky) in stone_possible)):
                        stone_possible.append((kx, ky))
                        stone_dic[(kx, ky)] = [(addx, addy)]
                    elif(((kx, ky) in stone_dic) and ((kx, ky) in stone_possible)):
                        stone_dic[(kx, ky)].append((addx, addy))
                    break
                else:
                    break
                px = px + addx
                py = py + addy
                p = (px, py)
    if(point in stone_possible):
        return True
    return False

def point2address(point):
    if(field_address[point] and field[point] == 0):
        return field_address[point]
    return z0

def show_result():
    black_stone = 0
    white_stone = 0
    for i in range(8):
        for j in range(8):
            stone = field[(i, j)]
            if(stone == 1):
                black_stone += 1
            elif(stone == 2):
                white_stone += 1
            else:
                pass
    s = ""
    winner = ""
    if(black_stone < white_stone):
        winner = "後手(白石)"
        s = "勝者は{0}".format(winner)
    elif(black_stone > white_stone):
        winner = "先手(黒石)"
        s = "勝者は{0}".format(winner)
    elif(black_stone == white_stone):
        s = "引き分け"
    else:
        winner = ""

    print("")
    print("===================")
    print("結果発表")
    print("黒石:{0}石".format(black_stone))
    print("白石:{0}石".format(white_stone))
    print("")
    print("よって、{0}です。".format(s))


def draw_stone(SURFACE, field):
    for i in range(8):
        for j in range(8):
            stone = field[(i, j)]
            ypos = 37.5 + (75 * i) - 30
            xpos = 137.5 + (75 * j) - 30
            if(stone == BLACK):
                pygame.draw.ellipse(SURFACE, 0x000000, ((xpos, ypos), (60, 60)))
            elif(stone == WHITE):
                pygame.draw.ellipse(SURFACE, 0x000000, ((xpos, ypos), (60, 60)), 5)
            elif(stone == EMPTY):
                pass
            else:
                print("error")
                sys.exti()

def draw_info(string_one, string_two, string_three, string_four):
    leftpos = 750
    sysfont_one = pygame.font.SysFont(None, 24)
    one = sysfont_one.render(string_one, True, (0, 0, 0))
    one_rect = one.get_rect()
    one_rect.left = leftpos
    one_rect.bottom = 100
    sysfont_two = pygame.font.SysFont(None, 24)
    two = sysfont_two.render(string_two, True, (0, 0, 0))
    two_rect = two.get_rect()
    two_rect.left = leftpos
    two_rect.bottom = 150
    sysfont_three = pygame.font.SysFont(None, 24)
    three = sysfont_three.render(string_three, True, (0, 0, 0))
    three_rect = three.get_rect()
    three_rect.left = leftpos
    three_rect.bottom = 200
    sysfont_four = pygame.font.SysFont(None, 24)
    four = sysfont_four.render(string_four, True, (0, 0, 0))
    four_rect = four.get_rect()
    four_rect.left = leftpos
    four_rect.bottom = 250
    x, y = -1, -1
    while(True):
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()
            if(event.type == MOUSEBUTTONDOWN and event.button == 1):
                x, y = event.pos[0], event.pos[1]
                break
        SURFACE.fill((255, 255, 255))
        weight = 5
        for xpos in range(100, 701, 75):
            pygame.draw.line(SURFACE, 0x000000, (xpos, 0), (xpos, 601), weight)
        for ypos in range(0, 601, 75):
            pygame.draw.line(SURFACE, 0x000000, (100, ypos), (701, ypos), weight)
        draw_stone(SURFACE, field)
        SURFACE.blit(one, one_rect)
        SURFACE.blit(two, two_rect)
        SURFACE.blit(three, three_rect)
        SURFACE.blit(four, four_rect)
        pygame.display.update()
        FPSCLOCK.tick(3)
        if(x >= 0 and y >= 0):
            break

def player_turn():
    fontsize = 36
    leftpos = 750
    sysfont_turn = pygame.font.SysFont(None, fontsize)
    turn = sysfont_turn.render("TURN", True, (0, 0, 0))
    turn_rect = turn.get_rect()
    turn_rect.left = leftpos
    turn_rect.bottom = 100
    s = ""
    if(Player == BLACK):
        s = "BLACK"
    elif(Player == WHITE):
        s = "WHITE"
    sysfont_pt = pygame.font.SysFont(None, fontsize)
    pt = sysfont_pt.render(": Player   ({0})".format(s), True, (0, 0, 0))
    pt_rect = pt.get_rect()
    pt_rect.left = leftpos
    pt_rect.bottom = 150
    while(True):
        address = ""
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()
            if(event.type == MOUSEBUTTONDOWN and event.button == 1 and (event.pos[0] >= 100 and event.pos[0] < 700)):
                xpos, ypos = floor((event.pos[0]-100)/75), floor(event.pos[1]/75)
                address = field_address[(ypos, xpos)]
                break
        if(address in field_address):
            break
        # drawing line
        SURFACE.fill((255, 255, 255))
        weight = 5
        for xpos in range(100, 701, 75):
            pygame.draw.line(SURFACE, 0x000000, (xpos, 0), (xpos, 601), weight)
        for ypos in range(0, 601, 75):
            pygame.draw.line(SURFACE, 0x000000, (100, ypos), (701, ypos), weight)
        # drawing stone
        draw_stone(SURFACE, field)
        SURFACE.blit(turn, turn_rect)
        SURFACE.blit(pt, pt_rect)
        pygame.display.update()
        FPSCLOCK.tick(3)
    return address

def computer_turn():
    fontsize = 36
    leftpos = 750
    sysfont_turn = pygame.font.SysFont(None, fontsize)
    turn = sysfont_turn.render("TURN", True, (0, 0, 0))
    turn_rect = turn.get_rect()
    turn_rect.left = leftpos
    turn_rect.bottom = 100
    s = ""
    if(Computer == BLACK):
        s = "BLACK"
    elif(Computer == WHITE):
        s = "WHITE"
    sysfont_ct = pygame.font.SysFont(None, fontsize)
    ct = sysfont_ct.render(": Computer ({0})".format(s), True, (0, 0, 0))
    ct_rect = ct.get_rect()
    ct_rect.left = leftpos
    ct_rect.bottom = 150
    sysfont_click = pygame.font.SysFont(None, fontsize)
    click = sysfont_click.render("Click somewhere.", True, (0, 0, 0))
    click_rect = click.get_rect()
    click_rect.left = leftpos
    click_rect.bottom = 200
    x, y = -1, -1
    while(True):
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()
            if(event.type == MOUSEBUTTONDOWN and event.button == 1):
                x, y = event.pos[0], event.pos[1]
                break
        # drawing line
        SURFACE.fill((255, 255, 255))
        weight = 5
        for xpos in range(100, 701, 75):
            pygame.draw.line(SURFACE, 0x000000, (xpos, 0), (xpos, 601), weight)
        for ypos in range(0, 601, 75):
            pygame.draw.line(SURFACE, 0x000000, (100, ypos), (701, ypos), weight)
        # drawing stone
        draw_stone(SURFACE, field)
        SURFACE.blit(turn, turn_rect)
        SURFACE.blit(ct, ct_rect)
        SURFACE.blit(click, click_rect)
        pygame.display.update()
        FPSCLOCK.tick(3)
        if(x >= 0 and y >= 0): # クリック判定
            break

def draw_result():
    black_stone = 0
    white_stone = 0
    for i in range(8):
        for j in range(8):
            stone = field[(i, j)]
            if(stone == 1):
                black_stone += 1
            elif(stone == 2):
                white_stone += 1
            else:
                pass
    s = ""
    winner = ""
    if(black_stone < white_stone):
        winner = "Last hand (WHITE)."
        s = "Winner is {0}.".format(winner)
    elif(black_stone > white_stone):
        winner = "First hand (BLACK)."
        s = "Winner is {0}.".format(winner)
    elif(black_stone == white_stone):
        s = "Draw."
    else:
        winner = ""

    result_title = "Result."
    # 石の数え方
    bstring = "BLACK stone : {0}.".format(black_stone)
    wstring = "WHITE stone : {0}.".format(white_stone)
    string_winner = "{0}".format(s)
    draw_info(result_title, bstring, wstring, string_winner)

def draw_pass():
    black_stone = 0
    white_stone = 0
    for i in range(8):
        for j in range(8):
            stone = field[(i, j)]
            if(stone == 1):
                black_stone += 1
            elif(stone == 2):
                white_stone += 1
            else:
                pass
    result_title = "Result"
    pass_string = "There is nothing square\n"\
                  "that possible putting."
    bstring = "BLACK stone : {0}.".format(black_stone)
    wstring = "WHITE stone : {0}.".format(white_stone)
    draw_info(result_title, pass_string, bstring, wstring)

def draw_foul():
    if(TURN == Player):
        s  = "You"
    elif(TUNR == Computer):
        s = "Computer"
    else:
        s = ""
    result_title = "Result"
    foul_string = "{0} commited a foul.".format(s)
    draw_info(result_title, foul_string, "", "")

def main():
    # define
    global EMPTY
    EMPTY = 0
    global BLACK
    BLACK = 1
    global WHITE
    WHITE = 2
    global Player
    global Computer
    global TURN

    global field
    field = np.array([[0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0],
                      [0,0,0,2,1,0,0,0],
                      [0,0,0,1,2,0,0,0],
                      [0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0]])

    global field_address
    field_address = np.array([["a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1"],
                              ["a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"],
                              ["a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3"],
                              ["a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4"],
                              ["a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5"],
                              ["a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6"],
                              ["a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"],
                              ["a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8"]]) # 4

    global offset
    offset = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)]


    """ drawing title """
    sysfont_title = pygame.font.SysFont(None, 80)
    title = sysfont_title.render("othello(8×8).", True, (0, 0, 0))
    title_rect = title.get_rect()
    title_rect.center = (500, 200)
    sysfont_start = pygame.font.SysFont(None, 60)
    start = sysfont_start.render("start.", True, (255, 255, 255))
    start_rect = start.get_rect()
    start_rect.center = (500, 400)
    while(True):
        xpos = 0
        ypos = 0
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()
            if(event.type == MOUSEBUTTONDOWN and event.button == 1):
                xpos, ypos = event.pos[0], event.pos[1]
        if((xpos >= 425) and (xpos <= 575) and (ypos >= 375) and (ypos <= 425)):
            break
        SURFACE.fill((255, 255, 255))
        SURFACE.blit(title, title_rect)
        x = 150
        y = 50
        pygame.draw.rect(SURFACE, (0, 0, 0), ((500-(x/2), 400-(y/2)), (x, y)))
        SURFACE.blit(start, start_rect)
        pygame.display.update()
        FPSCLOCK.tick(3)


    """ drawing select first hand or late hand """
    bxpos, bypos = 300, 350
    wxpos, wypos = 700, 350
    radius = 100
    d = radius * 2 # diameter
    sysfont = pygame.font.SysFont(None, 60)
    select_black = sysfont.render("First hand.", True, (0, 0, 0))
    select_black_rect = select_black.get_rect()
    select_black_rect.center = (bxpos, 200)
    select_white = sysfont.render("Late hand.", True, (0, 0, 0))
    select_white_rect = select_white.get_rect()
    select_white_rect.center = (wxpos, 200)
    select_message = sysfont.render("Select First hand or Late hand.", True, (0, 0, 0))
    select_message_rect = select_message.get_rect()
    select_message_rect.center = (500, 100)
    while(True):
        xpos = 0
        ypos = 0
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()
            if(event.type == MOUSEBUTTONDOWN and event.button == 1):
                xpos, ypos = event.pos[0], event.pos[1]
        # calculate radius
        br = np.sqrt((xpos - bxpos)**2 + (ypos - bypos)**2)
        wr = np.sqrt((xpos - wxpos)**2 + (ypos - wypos)**2)
        if(br <= radius):
            Player = BLACK
            Computer = WHITE
            TURN = Player
            break
        elif(wr <= radius):
            Player = WHITE
            Computer = BLACK
            TURN = Computer
            break
        # drawing background
        SURFACE.fill((255, 255, 255))
        # Rect
        pygame.draw.ellipse(SURFACE, (0, 0, 0), ((bxpos-100, bypos-100), (d, d)))
        pygame.draw.ellipse(SURFACE, (0, 0, 0), ((wxpos-100, wypos-100), (d, d)), 10)
        # Font
        SURFACE.blit(select_black, select_black_rect)
        SURFACE.blit(select_white, select_white_rect)
        SURFACE.blit(select_message, select_message_rect)
        pygame.display.update()
        FPSCLOCK.tick(3)

    """ othello (8x8) """
    before_field = copy.copy(field)
    after_field = copy.copy(field)
    while(True):
        """ pygame """
        for event in pygame.event.get():
            if(event.type == QUIT):
                pygame.quit()
                sys.exit()

        """ othello """
        while(TURN != 0):
            if(TURN == BLACK):
                point, offset_list = bw_turn(BLACK)
                if(TURN == Player):
                    print("TURN : You")
                    if(point == (-1, -1)):  # pass判定
                        print("pass")
                        print(field)
                        TURN = WHITE
                        if((before_field == after_field).all()):  # 両者pass判定
                            print("両者passのため対局を終了")
                            draw_pass()
                            TURN = 0
                            break
                        before_field = copy.copy(after_field)
                        continue
                    address = player_turn()
                    print("石を置く場所 : {0} ".format(address))
                    point = address2point(address)
                    offset_list = point2offset(point, Player)
                    if(not(address_check(point, TURN))):  # 有効手判定
                        print("「{0}」は無効な手です。".format(address))
                        print("よって、対局を終了します。")
                        print(field)
                        draw_foul()
                        TURN = 0
                        break
                elif(TURN == Computer):
                    print("TURN : Computer")
                    if(point == (-1, -1)):  # pass判定
                        print("pass")
                        print(field)
                        TURN = WHITE
                        if((before_field == after_field).all()):  # 両者pass判定
                            print("両者passのため対局を終了")
                            draw_pass()
                            TURN = 0
                            break
                        before_field = copy.copy(after_field)
                        continue
                    computer_turn()
                    print("石を置く場所 : {0} ".format(point2address(point)))
                else:
                    print("error")
                    TURN = 0
                    break
                field = update_field(TURN, point, offset_list)
                print(field)
                print("")
                before_field = copy.copy(after_field)
                after_field = copy.copy(field)
                TURN = WHITE
            elif(TURN == WHITE):
                point, offset_list = bw_turn(WHITE)
                if(TURN == Player):
                    print("TURN : You")
                    if(point == (-1, -1)):  # pass判定
                        print("pass")
                        print(field)
                        TURN = BLACK
                        if((before_field == after_field).all()):  # 両者pass判定
                            print("両者passのため対局を終了")
                            TURN = 0
                            draw_pass()
                            break
                        before_field = copy.copy(after_field)
                        continue
                    address = player_turn()
                    print("石を置く場所 : {0} ".format(address))
                    point = address2point(address)
                    offset_list = point2offset(point, Player)
                    if(not(address_check(point, TURN))):  # 有効手判定
                        print("「{0}」は無効な手です。".format(address))
                        print(field)
                        draw_foul()
                        TURN = 0
                        break
                elif(TURN == Computer):
                    print("TURN : Computer")
                    if(point == (-1, -1)):  # pass判定
                        print("pass")
                        print(field)
                        TURN = BLACK
                        if((before_field == after_field).all()):  # 両者pass判定
                            print("両者passのため対局を終了")
                            draw_pass()
                            TURN = 0
                            break
                        before_field = copy.copy(after_field)
                        continue
                    computer_turn()
                    print("石を置く場所 : {0} ".format(point2address(point)))
                else:
                    print("error")
                    TURN = 0
                    break
                field = update_field(TURN, point, offset_list)
                print(field)
                print("")
                before_field = copy.copy(after_field)
                after_field = copy.copy(field)
                TURN = BLACK
            else:
                print("error")
                TURN = 0
                break
            if(len(np.where(field == 0)[0]) == 0):
                print("")
                print(field)
                print("")
                print("対局を終了します。")
                print("")
                show_result()
                draw_result()
                TURN = 0
                break

        """ drawing field """
        SURFACE.fill((255, 255, 255))
        weight = 5
        for xpos in range(100, 701, 75):
            pygame.draw.line(SURFACE, 0x000000, (xpos, 0), (xpos, 601), weight)
        for ypos in range(0, 601, 75):
            pygame.draw.line(SURFACE, 0x000000, (100, ypos), (701, ypos), weight)
        # drawing stone
        draw_stone(SURFACE, field)
        pygame.display.update()
        FPSCLOCK.tick(3)
    return field


if __name__ == '__main__':
    main()

スポンサードサーチ