五子棋算法

前几天看到的一个比较有意思的算法;然后 实现了一下;最后给它加了一个UI界面;

 

核心获胜逻辑如下:

 

def __color_continius(self, arr, color):
        """
        判断某一颜色的棋子最大连续个数
        """
        max_count = 1
        _count = 1
        for i in range(0, len(arr) - 1):
            x1, y1 = arr[i]
            x2, y2 = arr[i + 1]
            if self.__pieces[x1][y1] == color and self.__pieces[x2][y2] == color:
                _count += 1
            else:
                _count = 1
            if _count >= max_count:
                max_count = _count
        return max_count
    def __check_win(self, selected_x, selected_y, color):
        """
        判断某一颜色棋子的输赢,以当前棋子为中心,4子为半径判断四个方向即可
        """
        _row = []
        for x in range(selected_x - 4, selected_x + 5):
            if x >= 0 and x < self.__width:
                _row.append((x, selected_y))
        if self.__color_continius(_row, color) >= 5:
            return True
        _col = []
        for x in range(selected_y - 4, selected_y + 5):
            if x >= 0 and x < self.__height:
                _col.append((selected_x, x))
        if self.__color_continius(_col, color) >= 5:
            return True
        lb_rt = []
        for x in range(-4, 5):
            s_x = selected_x + x
            s_y = selected_y - x
            if s_x >= 0 and s_x < self.__width and s_y > 0 and s_y < self.__height:
                lb_rt.append((s_x, s_y))
        if self.__color_continius(lb_rt, color) >= 5:
            return True
        lt_rb = []
        for x in range(-4, 5):
            s_x = selected_x + x
            s_y = selected_y + x
            if s_x >= 0 and s_x < self.__width and s_y > 0 and s_y < self.__height:
                lt_rb.append((s_x, s_y))
        if self.__color_continius(lt_rb, color) >= 5:
            return True
        return False

    def __is_draw(self):
        """
        判断是否是和棋
        """
        is_draw = True
        for x in self.__pieces:
            for y in x:
                if y == Piece.NotDefiend:
                    is_draw = False
        return is_draw

 

 

所有代码如下;python版本

'''
blog:https://www.cnblogs.com/rianley
author: rianley
'''
from tkinter import *
from tkinter.messagebox import *
from enum import Enum
import sys
class Piece(Enum):
    White = 1
    Black = 2
    NotDefiend = 3
class Gobang:
    def __init__(self):
        """
        初始化
        """
        self.__root = Tk()
        self.__root.title("程小航版本五子棋")
        self.__width = 15
        self.__height = 15
        self.__radius = 30
        self.__w = (self.__width) * self.__radius * 2
        self.__h = (self.__height) * self.__radius * 2
        self.__root.geometry("{}x{}".format(self.__w, self.__h))
        self.__canvas = Canvas(self.__root, width=self.__w, height=self.__h)
        self.__last_x = -1
        self.__last_y = -1
        self.__last_point = None
        self.__color = Piece.White
        self.__pieces = [[Piece.NotDefiend for y in range(0, self.__height)] for x in range(0, self.__width)]
    def __draw_lines(self):
        for x in range(0, self.__width):
            self.__canvas.create_line(self.__radius + x * self.__radius * 2,
                                      self.__radius,
                                      self.__radius + x * self.__radius * 2,
                                      self.__radius + (self.__height - 1) * self.__radius * 2)
        for y in range(0, self.__height):
            self.__canvas.create_line(self.__radius,
                                      self.__radius + y * self.__radius * 2,
                                      self.__radius + (self.__width - 1) * self.__radius * 2,
                                      self.__radius + y * self.__radius * 2)
    def __get_current_position(self, x, y):
        """
        根据当前鼠标位置计算棋子位置
        """
        selected_x = max(0, min(int(x / (self.__radius * 2)), self.__width - 1))
        selected_y = max(0, min(int(y / (self.__radius * 2)), self.__height - 1))
        return (selected_x, selected_y)
    def __color_continius(self, arr, color):
        """
        判断某一颜色的棋子最大连续个数
        """
        max_count = 1
        _count = 1
        for i in range(0, len(arr) - 1):
            x1, y1 = arr[i]
            x2, y2 = arr[i + 1]
            if self.__pieces[x1][y1] == color and self.__pieces[x2][y2] == color:
                _count += 1
            else:
                _count = 1
            if _count >= max_count:
                max_count = _count
        return max_count
    def __check_win(self, selected_x, selected_y, color):
        """
        判断某一颜色棋子的输赢,以当前棋子为中心,4子为半径判断四个方向即可
        """
        _row = []
        for x in range(selected_x - 4, selected_x + 5):
            if x >= 0 and x < self.__width:
                _row.append((x, selected_y))
        if self.__color_continius(_row, color) >= 5:
            return True
        _col = []
        for x in range(selected_y - 4, selected_y + 5):
            if x >= 0 and x < self.__height:
                _col.append((selected_x, x))
        if self.__color_continius(_col, color) >= 5:
            return True
        lb_rt = []
        for x in range(-4, 5):
            s_x = selected_x + x
            s_y = selected_y - x
            if s_x >= 0 and s_x < self.__width and s_y > 0 and s_y < self.__height:
                lb_rt.append((s_x, s_y))
        if self.__color_continius(lb_rt, color) >= 5:
            return True
        lt_rb = []
        for x in range(-4, 5):
            s_x = selected_x + x
            s_y = selected_y + x
            if s_x >= 0 and s_x < self.__width and s_y > 0 and s_y < self.__height:
                lt_rb.append((s_x, s_y))
        if self.__color_continius(lt_rb, color) >= 5:
            return True
        return False

    def __is_draw(self):
        """
        判断是否是和棋
        """
        is_draw = True
        for x in self.__pieces:
            for y in x:
                if y == Piece.NotDefiend:
                    is_draw = False
        return is_draw
    def __bind_mouse_functions(self):
        """
        绑定鼠标事件
        """
        def move_handler(event):
            """
            鼠标移过棋盘,显示棋子
            """
            selected_x, selected_y = self.__get_current_position(event.x, event.y)
            # 如果已经有棋子了,当鼠标移动到点上时显示红色
            color = ("black" if self.__color == Piece.Black else "white") if self.__pieces[selected_x][
                                                                                 selected_y] == Piece.NotDefiend else "red"
            if selected_x != self.__last_x or selected_y != self.__last_y:
                self.__canvas.delete(self.__last_point)
                self.__last_point = self.__canvas.create_oval(
                    self.__radius + selected_x * self.__radius * 2 - self.__radius,
                    self.__radius + selected_y * self.__radius * 2 - self.__radius,
                    self.__radius + selected_x * self.__radius * 2 + self.__radius,
                    self.__radius + selected_y * self.__radius * 2 + self.__radius,
                    fill=color)
                self.__last_x = selected_x
                self.__last_y = selected_y
        def click_handler(event):
            """
            鼠标点击棋盘,落子并判断输赢
            """
            selected_x, selected_y = self.__get_current_position(event.x, event.y)
            if self.__pieces[selected_x][selected_y] != Piece.NotDefiend:
                # 棋子已经存在,不可落子
                pass
            else:
                self.__pieces[selected_x][selected_y] = self.__color
                color = "black" if self.__color == Piece.Black else "white"
                self.__canvas.create_oval(self.__radius + selected_x * self.__radius * 2 - self.__radius,
                                          self.__radius + selected_y * self.__radius * 2 - self.__radius,
                                          self.__radius + selected_x * self.__radius * 2 + self.__radius,
                                          self.__radius + selected_y * self.__radius * 2 + self.__radius,
                                          fill=color)
                # 如果某一方赢了,则重置游戏
                if self.__check_win(selected_x, selected_y, self.__color):
                    message = "{} win!".format(color)
                    showinfo("Info", message)
                    self.__reset()
                # 否则判断是否是和棋,如果是和棋,则重置
                elif self.__is_draw():
                    message = "draw chess!"
                    showinfo("Info", message)
                    self.__reset()
                if self.__color == Piece.White:
                    self.__color = Piece.Black
                else:
                    self.__color = Piece.White
        #绑定事件canvas事件
        self.__canvas.bind('<Motion>', move_handler)
        self.__canvas.bind('<Button-1>', click_handler)
    def __reset(self):
        """
        重置游戏
        """
        self.__canvas.quit()
        self.__root.quit()
        self.__root.destroy()
        self.__init__()
        self.start()
    def start(self):
        # 绘制棋盘
        self.__canvas.pack()
        #绘制线
        self.__draw_lines()
        #鼠标经过是处理落棋,判断胜负条件
        self.__bind_mouse_functions()
        #循环执行
        self.__root.mainloop()
if __name__ == "__main__":
    gobang = Gobang()
    gobang.start()

 

朋友写的 js版本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>五子棋</title>
    <style type="text/css">
        canvas{
            display: block;
            margin: 50px auto;
            box-shadow: -2px -2px 2px #F3F2F2, 5px 5px 5px #6F6767;
        }
    </style>
</head>
<body>
<canvas id="mycanvas" width="600px" height="600px"></canvas>
<script type="text/javascript">
    var chess = document.getElementById("mycanvas");
    var context = chess.getContext('2d');
    var me = true;
    var chessBox = [];//用于存放棋盘中落子的情况
    for(var i=0;i<20;i++){
        chessBox[i]=[];
        for(var j=0;j<20;j++){
            chessBox[i][j]=0;//初始值为0
        }
    }
    function drawChessBoard(){
        for(var i=0;i<20;i++){
            context.strokeStyle="#D6D1D1";
            context.moveTo(15+i*30,15);//垂直方向画15根线,相距30px;
            context.lineTo(15+i*30,585);
            context.stroke();
            context.moveTo(15,15+i*30);//水平方向画15根线,相距30px;棋盘为14*14;
            context.lineTo(585,15+i*30);
            context.stroke();
        }
    }
    drawChessBoard();//绘制棋盘
    function oneStep(i,j,k){
        context.beginPath();
        context.arc(15+i*30,15+j*30,13,0,2*Math.PI);//绘制棋子
        var g=context.createRadialGradient(15+i*30,15+j*30,13,15+i*30,15+j*30,0);//设置渐变
        if(k){    //k=true是黑棋,否则是白棋
            g.addColorStop(0,'#0A0A0A');//黑棋
            g.addColorStop(1,'#636766');
        }else {
            g.addColorStop(0,'#D1D1D1');//白棋
            g.addColorStop(1,'#F9F9F9');
        }
        context.fillStyle=g;
        context.fill();
        context.closePath();
    }
    var n=19;
    function f_x(arr) {
        for(var i in arr){
            let len = 1;
            let res = arr[i].split('_');
            let x = res[0];
            let y = res[1];
            let left = x;
            let right = x;
            while (left >= 0){
                left -= 1
                if(arr.includes(left+'_'+y)){
                    len+=1;
                }else{
                    break;
                }
            }

            while (right <= n){
                right += 1
                if(arr.includes(right+'_'+y)){
                    len+=1;
                }else{
                    break;
                }
            }
            if(len >= 5){
                return arr[i];
            }
        }
        return  false;
    }

    function f_y(arr) {
        for(var i in arr){
            let len = 1;
            let res = arr[i].split('_');
            let x = res[0];
            let y = res[1];
            let left = y;
            let right = y;
            while (left >= 0){
                left -= 1
                if(arr.includes(x+'_'+left)){
                    len+=1;
                }else{
                    break;
                }
            }

            while (right <= n){
                right += 1
                if(arr.includes(x+'_'+right)){
                    len+=1;
                }else{
                    break;
                }
            }
            if(len >= 5){
                return arr[i];
            }
        }
        return  false;
    }

    function f_xy1(arr) {
        for(var i in arr){
            let len = 1;
            let res = arr[i].split('_');
            let x = res[0];
            let y = res[1];
            let left = x;
            let right = y;
            while (left >= 0 && right >= 0){
                left -= 1
                right -= 1
                if(arr.includes(left+'_'+right)){
                    len+=1;
                }else{
                    break;
                }
            }
            left = x;
            right = y;
            while (right <= n && left <= n){
                left += 1
                right += 1
                if(arr.includes(left+'_'+right)){
                    len+=1;
                }else{
                    break;
                }
            }
            if(len >= 5){
                return arr[i];
            }
        }
        return  false;
    }

    function f_xy2(arr) {
        for(var i in arr){
            let len = 1;
            let res = arr[i].split('_');
            let x = res[0];
            let y = res[1];
            let left = x;
            let right = y;
            while (left >= 0 && right <= n){
                left -= 1
                right += 1
                if(arr.includes(left+'_'+right)){
                    len+=1;
                }else{
                    break;
                }
            }
            left = x;
            right = y;
            while (right >= 0 && left <= n){
                left += 1
                right -= 1
                if(arr.includes(left+'_'+right)){
                    len+=1;
                }else{
                    break;
                }
            }
            if(len >= 5){
                return arr[i];
            }
        }
        return  false;
    }

    var arr_all = [];
    var arr1 = [];
    var arr2 = [];
    var setIntervalxxx = setInterval(function () {
        while (1){
            var a = Math.floor(Math.random() * 20);
            var b = Math.floor(Math.random() * 20);
            var strs = a+'_'+b;
            if(arr_all.includes(strs)){
                continue;
            }else{
                break;
            }
        }

        arr_all.push(strs);
        if(arr1.length == arr2.length){
            arr1.push(strs);
            oneStep(a,b,true);
            var r1 = f_x(arr1);
            var r2 = f_y(arr1);
            var r3 = f_xy1(arr1);
            var r4 = f_xy2(arr1);
            if(r1 || r2 || r3 || r4){
                alert('黑棋赢!!!');
                console.log(r1,r2,r3,r4,'黑棋赢!!!',arr1);
                clearInterval(setIntervalxxx);
            }
        }else{
            arr2.push(strs);
            oneStep(a,b,false);
            var r1 = f_x(arr2);
            var r2 = f_y(arr2);
            var r3 = f_xy1(arr2);
            var r4 = f_xy2(arr2);
            if(r1 || r2 || r3 || r4){
                alert('白棋赢!!!');
                console.log(r1,r2,r3,r4,'白棋赢!!!',arr2);
                clearInterval(setIntervalxxx);
            }
        }
    },200);


    chess.onclick=function(e){
        var x = e.offsetX;//相对于棋盘左上角的x坐标
        var y = e.offsetY;//相对于棋盘左上角的y坐标
        var i = Math.floor(x/30);
        var j = Math.floor(y/30);
        if( chessBox[i][j] == 0 ) {
            oneStep(i,j,me);
            if(me){
                chessBox[i][j]=1;

            }else{
                chessBox[i][j]=2;

            }
            me=!me;//下一步白棋
        }
    }
</script>
</body>
</html>

 

posted @ 2021-06-30 17:04  rianley  阅读(435)  评论(0编辑  收藏  举报