Bootstrap

python实现五子棋小游戏项目(含免费源码下载链接)

一、前言

python实现的五子棋运行游戏,源码下载链接放在了文章结尾!

这是一个五子棋小游戏,在局域网内可以双人对战,又分为服务器和客户端部分,在windows环境多次测试均运行正常。

二、主要思路

1、局域网对战

对于局域网功能来说,首先建立连接(tcp),然后每次下棋时将棋子的坐标发送给对方,当接收到坐标后实例化成棋子对象,这 个接收时用了select函数,因为pygame需要循环渲染图片,所以要用非阻塞方式接收消息

select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管 是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核 根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读或可写,主要用于Socket通信当中。

2、电脑对战

电脑对战的思路也很简单,用了应该是最常见的也是最简单的方法,就是循环遍历棋盘的每一个点,判断该点的价值,选取价值最 大的点落子,这个需要对五子棋的棋型有一定了解,这里介绍几种常见的棋型(约定1为己方棋子,2为对方棋子,0为空)

活四(011110):这时候四颗棋子相连,同时两端为空,已经阻止不了一方的胜利了,此时价值应该设置最高
死四(011112|10111|11011):四颗棋子,只有一个地方能形成连五,如果是自己的棋可以赢,是对方的也可以阻止对方赢棋,此时价值次高
......

就这样把每种棋型判断一下,获得该点的价值,电脑选择落子位置时,要判断是进攻还是防守,需要两次遍历棋盘,获取进攻时的 最大价值和防守的最大价值。

3、main.y

# encoding:utf-8
import pygame
from pygame.locals import *
import sys
import math
from gobang_client import storn
from socket import *
import select
from tkinter import *

pygame.init()
pygame.mixer.init()

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# 棋盘
x = []
y = []
for i in range(0, 15):
    x.append(28 + i * 40)
    y.append(28 + i * 40)

# 记录棋盘每个坐标的属性,没有棋子为0,白棋为1,黑棋为2
map_chess = {}


# 判断是否有子
def is_empty(me):
    global map_chess
    a = False
    if map_chess[str(me[0]) + '|' + str(me[1])]:
        a = True
    return a


# 判断是否有五子连线
def iswin(targert):
    x = []
    y = []
    for i in range(0, 15):
        x.append(28 + i * 40)
    for i in range(0, 15):
        y.append(28 + i * 40)
    for each in targert:
        (a, b) = each.location()

        # x轴方向
        num_x = 0
        c = a - 40
        d = a + 40
        while c > 0:
            isbreak = True
            for i in targert:
                if i.location() == (c, b):
                    num_x += 1
                    isbreak = False
            if not isbreak:
                c -= 40
            else:
                break
        while d < 615:
            isbreak = True
            for i in targert:
                if i.location() == (d, b):
                    num_x += 1
                    isbreak = False
            if not isbreak:
                d += 40
            else:
                break
        num_x += 1

        # y轴方向
        num_y = 0
        e = b - 40
        f = b + 40
        while e > 0:
            isbreak = True
            for i in targert:
                if i.location() == (a, e):
                    num_y += 1
                    isbreak = False
            if not isbreak:
                e -= 40
            else:
                break
        while f < 615:
            isbreak = True
            for i in targert:
                if i.location() == (a, f):
                    num_y += 1
                    isbreak = False
            if not isbreak:
                f += 40
            else:
                break
        num_y += 1

        # 西北,东南方向
        num_en = 0
        c1 = a - 40
        c2 = b - 40
        c3 = a + 40
        c4 = b + 40
        while c1 > 0 and c2 > 0:
            isbreak = True
            for i in targert:
                if i.location() == (c1, c2):
                    num_en += 1
                    isbreak = False
            if not isbreak:
                c1 -= 40
                c2 -= 40
            else:
                break
        while c3 < 615 and c4 < 615:
            isbreak = True
            for i in targert:
                isbreak = True
                if i.location() == (c3, c4):
                    num_en += 1
                    isbreak = False
            if not isbreak:
                c3 += 40
                c4 += 40
            else:
                break
        num_en += 1

        # 东北,西南方向
        num_wn = 0
        c5 = a + 40
        c6 = b - 40
        c7 = a - 40
        c8 = b + 40
        while c5 < 615 and c6 > 0:
            isbreak = True
            for i in targert:
                if i.location() == (c5, c6):
                    num_wn += 1
                    isbreak = False
            if not isbreak:
                c5 += 40
                c6 -= 40
            else:
                break
        while c7 > 0 and c8 < 615:
            isbreak = True
            for i in targert:
                isbreak = True
                if i.location() == (c7, c8):
                    num_wn += 1
                    isbreak = False
            if not isbreak:
                c7 -= 40
                c8 += 40
            else:
                break
        num_wn += 1
        if num_x >= 5 or num_y >= 5 or num_en >= 5 or num_wn >= 5:
            return True
    return False


# 判断每个点的价值
def point_value(pos, identify1, identify2):
    value = 0
    for i in range(1, 9):
        # *1111_ 活四
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == identify1 and \
                get_point(pos, i, 5) == 0:
            value += 40000
        # *11112 死四1
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == identify1 and \
                get_point(pos, i, 5) == identify2:
            value += 30000
        # 1*111 死四2
        if get_point(pos, i, -1) == identify1 and \
                get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1:
            value += 30000
        # 11*11 死四3
        if get_point(pos, i, -2) == identify1 and \
                get_point(pos, i, -1) == identify1 and \
                get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1:
            value += 30000
        # *111_ 活三1
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == 0:
            value += 20000
        # *1_11_ 活三2
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == identify1 and \
                get_point(pos, i, 5) == 0:
            value += 20000
        # *1112 死三1
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == identify2:
            value += 15000
        # _1_112 死三2
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == identify1 and \
                get_point(pos, i, 5) == identify2:
            value += 15000
        # _11_12 死三3
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == 0 and \
                get_point(pos, i, 4) == identify1 and \
                get_point(pos, i, 5) == identify2:
            value += 15000
        # 1__11 死三4
        if get_point(pos, i, -1) == identify1 and \
                get_point(pos, i, 1) == 0 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1:
            value += 15000
        # 1_1_1 死三5
        if get_point(pos, i, -1) == identify1 and \
                get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0 and \
                get_point(pos, i, 3) == identify1:
            value += 15000
        # 2_111_2 死三6
        if get_point(pos, i, -1) == identify2 and \
                get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == 0 and \
                get_point(pos, i, 5) == identify2:
            value += 15000
        # __11__ 活二1
        if get_point(pos, i, -1) == 0 and \
                get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == identify1 and \
                get_point(pos, i, 3) == 0 and \
                get_point(pos, i, 4) == 0:
            value += 1000
        # _1_1_ 活二2
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0 and \
                get_point(pos, i, 3) == identify1 and \
                get_point(pos, i, 4) == 0:
            value += 1000
        # *1__
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0 and \
                get_point(pos, i, 3) == 0:
            value += 30
        # *1_
        if get_point(pos, i, 1) == identify1 and \
                get_point(pos, i, 2) == 0:
            value += 20
        # *1
        if get_point(pos, i, 1) == identify1:
            value += 10
    return value


# 电脑选取落子的位置
def ai():
    value = max1 = max2 = 0
    pos1 = pos2 = ()
    # 进攻时
    for i in range(0, 15):
        row = 28 + i * 40
        for j in range(0, 15):
            col = 28 + j * 40
            pos = (row, col)
            if is_empty(pos):
                continue
            value = point_value(pos, 1, 2)
            if value > max1:
                max1 = value
                pos1 = (row, col)

    # 防守时
    for i in range(0, 15):
        for j in range(0, 15):
            row = 28 + i * 40
            col = 28 + j * 40
            if is_empty((row, col)):
                continue
            value = point_value((row, col), 2, 1)
            if value > max2:
                max2 = value
                pos2 = (row, col)
    if max1 > max2:
        return pos1
    else:
        return pos2


# 获取当前坐标的属性,返回1代表白棋,返回2代表黑棋,返回3代表没有棋
def get_point(pos, src, offset):
    # 8个方向
    global map_chess
    directions = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]
    x1, y1 = pos
    x1 = x1 + directions[src - 1][0] * offset * 40
    y1 = y1 + directions[src - 1][1] * offset * 40
    if x1 > 588 or y1 > 588 or x1 < 28 or y1 < 28:
        return 5
    else:
        return map_chess[str(x1) + '|' + str(y1)]


# 初始化棋盘
def init():
    global map_chess
    for i in x:
        for j in y:
            map_chess[str(i) + '|' + str(j)] = 0


def main():
    # TCP服务
    BUFSIZ = 2048
    tcpclisock = socket(AF_INET, SOCK_STREAM)

    bg_size = 615, 615

    # 输入IP地址
    def gui():
        top = Tk()
        top.title('IP')
        top.geometry('300x200')
        HOST = ''
        POST = 21578
        nonlocal tcpclisock

        def fun():
            nonlocal HOST
            nonlocal POST
            nonlocal tcpclisock
            HOST = E1.get()
            ADDR = (HOST, POST)
            try:
                tcpclisock.connect(ADDR)
                L2 = Label(top, text='', font='华文行楷')
                L2 = Label(top, text='已连接', font='华文行楷')
                L2.grid(row=2, column=1)
            except error:
                L2 = Label(top, text='连接失败', font='华文行楷')
                L2.grid(row=2, column=1)

        L1 = Label(top, text='    IP 地址:', font='宋体', padx=5, pady=30)
        L1.grid(row=1, column=0)
        E1 = Entry(top, font='华文行楷')
        E1.grid(row=1, column=1)
        B1 = Button(top, text='连接', font='宋体', padx=1, command=fun)
        B1.grid(row=2, column=0)

        mainloop()

    screen = pygame.display.set_mode(bg_size)
    pygame.display.set_caption('五子棋')
    bg_image = pygame.image.load('image/bg.png').convert_alpha()  # 背景图片

    # 背景音乐
    bg_sound = pygame.mixer.music.load('sound/bg_music.mp3')
    pygame.mixer.music.set_volume(0.2)
    pygame.mixer.music.play(-1)

    running = True

    clock = pygame.time.Clock()

    inputs = [tcpclisock]

    # 棋子
    white_chesses = []
    black_chesses = []
    chesses = []

    # 标志轮到哪方下棋
    is_play = True

    # 标志是否连接
    islink = False

    # 标志是否结束游戏
    result = False

    # 标志赢方
    black_win = False
    white_win = False

    # 标志人与人
    is_people = False

    # 标志人与电脑
    is_ai = False

    # 标志是否做出选择
    is_choise = False

    # 标志是否关闭声音
    is_have_sound = True

    # 标志是否再来 一局
    is_playagain = False

    # 对面是否发来重新开始的消息
    is_recieve1 = False

    # 对面拒绝了重新开始
    is_recieve2 = False

    # 输赢
    font1 = pygame.font.Font('font/12345.TTF', 30)
    win_text = font1.render(u"你赢了!!!", True, WHITE)
    win_text_rect = win_text.get_rect()
    win_text_rect.left, win_text_rect.top = (bg_size[0] - win_text_rect.width) // 2, \
                                            (bg_size[1] - win_text_rect.height) // 2
    lose_text = font1.render(u"垃圾...", True, WHITE)
    lose_text_rect = lose_text.get_rect()
    lose_text_rect.left, lose_text_rect.top = (bg_size[0] - lose_text_rect.width) // 2, \
                                              (bg_size[1] - lose_text_rect.height) // 2
    play_text = font1.render(u"再玩一局", True, WHITE)
    play_text_rect = play_text.get_rect()
    menu_text = font1.render(u'主菜单', True, WHITE)
    menu_text_rect = menu_text.get_rect()

    # 登入选项
    text1 = font1.render(u"玩家与玩家", True, WHITE)
    text1_rect = text1.get_rect()
    text1_rect.left, text1_rect.top = (bg_size[0] - text1_rect.width) // 2, \
                                      (bg_size[1] - text1_rect.height) // 2 - 100
    text2 = font1.render(u'玩家与电脑', True, WHITE)
    text2_rect = text2.get_rect()
    text2_rect.left, text2_rect.top = (bg_size[0] - text1_rect.width) // 2, \
                                      (bg_size[1] - text1_rect.height) // 2
    text3 = font1.render(u'声音:  开', True, WHITE)
    text3_rect = text3.get_rect()
    text3_rect.left, text3_rect.top = (bg_size[0] - text3_rect.width) // 2, \
                                      (bg_size[1] - text3_rect.height) // 2 + 100
    text4 = font1.render(u'声音:  关', True, WHITE)
    text4_rect = text4.get_rect()
    text4_rect.left, text4_rect.top = (bg_size[0] - text4_rect.width) // 2, \
                                      (bg_size[1] - text4_rect.height) // 2 + 100
    text5 = font1.render(u'对方表示你很菜\n并断开了连接', True, WHITE)
    text5_rect = text5.get_rect()
    text5_rect.left, text5_rect.top = (bg_size[0] - text5_rect.width) // 2, \
                                      (bg_size[1] - text5_rect.height) // 2
    text6 = font1.render(u'对方再次向你发起挑战', True, WHITE)
    text6_rect = text6.get_rect()
    text6_rect.left, text6_rect.top = (bg_size[0] - text6_rect.width) // 2, \
                                      (bg_size[1] - text6_rect.height) // 2
    text7 = font1.render(u'接受挑战         返回主菜单', True, WHITE)
    text7_rect = text7.get_rect()
    text7_rect.left, text7_rect.top = (bg_size[0] - text7_rect.width) // 2, \
                                      (bg_size[1] - text7_rect.height) // 2 + 100

    # 初始化
    init()

    while running:

        screen.blit(bg_image, (0, 0))

        # 绘制选项
        if not is_choise:
            screen.blit(text1, text1_rect)
            screen.blit(text2, text2_rect)
            if not is_have_sound:
                screen.blit(text4, text4_rect)
            else:
                screen.blit(text3, text3_rect)

        # 绘制棋盘
        if is_choise:
            if chesses:
                for i in chesses:
                    screen.blit(i.image, i.image_rect())

        for event in pygame.event.get():
            if event.type == QUIT:
                if is_people:
                    tcpclisock.close()
                pygame.quit()
                sys.exit()

            if event.type == MOUSEBUTTONDOWN:
                if event.button == 1:

                    if is_choise:
                        pos = pygame.mouse.get_pos()
                        # 判断是否连接是否是自己下棋时间
                        if is_play and not is_recieve1 and not result:
                            me = storn.Storn_White(pos)
                            if not is_empty(me.location()):
                                white_chesses.append(me)
                                chesses.append(me)
                                map_chess[str(me.location()[0]) + '|' + str(me.location()[1])] = 1
                                if is_people:
                                    tcpclisock.send(str(pos).encode('utf8'))
                                is_play = False
                            else:
                                del (me)
                    else:
                        pos = pygame.mouse.get_pos()
                        if text1_rect.left <= pos[0] <= text1_rect.left + 170 and \
                                text1_rect.top <= pos[1] <= text1_rect.top + 30:
                            is_choise = True
                            is_people = True
                            gui()
                        if text1_rect.left <= pos[0] <= text1_rect.left + 170 and \
                                text1_rect.top + 100 <= pos[1] <= text1_rect.top + 130:
                            is_choise = True
                            is_ai = True
                        if text1_rect.left <= pos[0] <= text1_rect.left + 160 and \
                                text1_rect.top + 200 <= pos[1] <= text1_rect.top + 230:
                            is_have_sound = not is_have_sound
                            if not is_have_sound:
                                pygame.mixer.stop()
                                pygame.mixer.music.stop()
                            else:
                                pygame.mixer.music.play()

                    # 对面发来请求时
                    if result:
                        if not is_recieve1 and not is_recieve2:
                            pos = pygame.mouse.get_pos()
                            if win_text_rect.left < pos[0] < win_text_rect.right - 50 and \
                                    win_text_rect.top < pos[1] < win_text_rect.top + 30:
                                if is_people:
                                    tcpclisock.send('again'.encode('utf8'))
                                if is_ai:
                                    is_playagain = True
                                    is_play = True
                                    result = False
                                    init()

                            if win_text_rect.left < pos[0] < win_text_rect.right and \
                                    win_text_rect.top + 50 < pos[1] < win_text_rect.top + 120:
                                is_people = False
                                if islink:
                                    islink = False
                                    tcpclisock.send('no'.encode('utf8'))
                                tcpclisock.close()
                                main()

                    if is_recieve2:
                        pos = pygame.mouse.get_pos()
                        if text5_rect.left + 150 < pos[0] < text5_rect.left + 250 and \
                                text5_rect.top + 70 < pos[1] < text5_rect.top + 190:
                            main()

                    if is_recieve1:
                        pos = pygame.mouse.get_pos()
                        if text7_rect.left < pos[0] < text7_rect.left + 150 and \
                                text7_rect.top < pos[1] < text7_rect.top + 120:
                            tcpclisock.send('yes'.encode('utf8'))
                            result = False
                            white_win = False
                            black_win = False
                            is_recieve1 = False
                            is_playagain = True
                            is_play = True
                        if text7_rect.left + 190 < pos[0] < text7_rect.left + 330 and \
                                text7_rect.top < pos[1] < text7_rect.top + 120:
                            tcpclisock.send('no'.encode('utf8'))
                            main()

        # 电脑落子
        if is_ai and not is_play:
            me = storn.Storn_Black(ai())
            black_chesses.append(me)
            chesses.append(me)
            map_chess[str(me.location()[0]) + '|' + str(me.location()[1])] = 2
            is_play = True

        # 接收cli的消息
        if is_people:
            rs, ws, es = select.select(inputs, [], [], 0)
            for r in rs:
                if r is tcpclisock:
                    try:
                        data = r.recv(BUFSIZ)
                        islink = True
                        disconnected = not data
                        print(data.decode('utf8'))
                        if data.decode('utf8') == 'again':
                            is_recieve1 = True
                        if data.decode('utf8') == 'yes':
                            is_playagain = True
                            is_play = True
                        if data.decode('utf8') == 'no':
                            is_recieve2 = True
                            islink = False
                        if not is_play and not result:
                            me = storn.Storn_Black(eval(data))
                            black_chesses.append(me)
                            chesses.append(me)
                            is_play = True
                    except error:
                        disconnected = True
                        islink = False

        # 判断输赢
        if not result and iswin(black_chesses):
            result = True;
            black_win = True
        if not result and iswin(white_chesses):
            result = True
            white_win = True

        if black_win and result and not is_recieve1 and not is_recieve2:
            screen.blit(lose_text, (win_text_rect.left, win_text_rect.top - 80))
            screen.blit(play_text, win_text_rect)
            screen.blit(menu_text, (win_text_rect.left, win_text_rect.top + 80))

        if white_win and result and not is_recieve1 and not is_recieve2:
            screen.blit(win_text, (win_text_rect.left, win_text_rect.top - 80))
            screen.blit(play_text, win_text_rect)
            screen.blit(menu_text, (win_text_rect.left, win_text_rect.top + 80))

        if is_recieve1:
            screen.blit(text6, text6_rect)
            screen.blit(text7, text7_rect)

        if is_recieve2:
            screen.blit(text5, text5_rect)
            screen.blit(menu_text, (text5_rect.left + 150, text5_rect.top + 70))

        if is_playagain:
            init()
            white_chesses.clear()
            black_chesses.clear()
            chesses.clear()
            result = False
            black_win = False
            white_win = False
            is_playagain = False

        pygame.display.flip()

        clock.tick(60)


if __name__ == '__main__':
    main()

三、游戏截图

资源下载链接

【免费】python实现五子棋小游戏源码.zip资源-CSDN文库

;