精华内容
下载资源
问答
  • 评论功能简单实现

    千次阅读 2021-02-28 16:43:48
    最近在写一个问答功能,类似于评论,几番找资料才有点感觉(主要是太菜了),为了加深印象就单独抽出来记下笔记,然后这篇写完就开始SpringBoot的复习了1. 说明网上看到有三种类型的评论,按照笔者的理解记下了过程...

    最近在写一个问答功能,类似于评论,几番找资料才有点感觉(主要是太菜了),为了加深印象就单独抽出来记下笔记,然后这篇写完就开始SpringBoot的复习了

    1. 说明

    网上看到有三种类型的评论,按照笔者的理解记下了过程(可能理解错了,望大神指出),所以列出的是笔者的理解,下面以模拟博客评论的场景来说明,(这些类型是笔者形容的,并没有这个词),总觉得很慌理解错了,希望大家评论指正

    测试环境:SSM、JDK1.8

    2. 没有互动型

    这种类型只能评论,评论之间没有互动,类似于问答形式。提出问题,然后回答,一对多关系。这些回答之间没有任何联系

    c45f3fa9943a55b75a7e5e18eecb8f70.png

    从图可以简单看出,这种类型的评论是比较简单的,设计一个评论表,其内部添加一个挂载的博客id字段即可

    数据库设计

    CREATE TABLE `comment` (

    `comment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论的id',

    `nickname` varchar(255) DEFAULT NULL COMMENT '评论者的昵称',

    `content` varchar(255) DEFAULT NULL COMMENT '评论的内容',

    `blog_id` int(11) DEFAULT NULL COMMENT '评论挂载的博客id',

    PRIMARY KEY (`comment_id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    这里主要说明评论功能的实现,表会尽可能简单的设计,像点赞,分页,图像这些不再考虑范围内,另一个blog表也没有给出,可以自行理解

    查询语句

    SELECT * FROM comment WHERE blog_id = #{blog_id}

    传入需要查询评论的博客id即可,将查询的内容放入其评论区完成,这种评论较为简单,评论之间没有互动,适用于少数场景(像笔者这次写的问答功能,但该问答有非法关键词,官方回答,锁定,审核,等功能,也不简单)

    3. 套娃型

    这种类型笔者见得比较少,因为像树状,评论多起来层级结构复杂,不人性化

    da423007c1c7d15d71903aaf4dded751.png

    小一评论博客,小二紧接着回复小一的评论,小三又回复小二的评论,小一又回了小三的评论,像俄罗斯套娃层层套

    数据库设计

    这里笔者用单表来实现,笔者称评论与回复这二者为父子关系,评论为父级,回复为子级,这种关系在数据里增多一个parent_id字段来维护,默认为-1,表示没有父级

    CREATE TABLE `blog` (

    `comment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论的id',

    `nickname` varchar(255) DEFAULT NULL COMMENT '评论者的昵称',

    `content` varchar(255) DEFAULT NULL COMMENT '评论的内容',

    `blog_id` int(11) DEFAULT NULL COMMENT '评论挂载的博客id',

    `parent_id` int(11) DEFAULT '-1' COMMENT '父级评论',

    PRIMARY KEY (`comment_id`)

    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

    博客评论多起来的时,可用blog_id作为索引(不想增加与功能无关内容,假装没看到)

    Dto、映射文件、Service层

    由于使用mybatis,所以把映射文件放上来一目了然

    public class CommentDTO {

    private int id;

    private String nickname;

    private String content;

    private List children; // 存放子级的回复

    // getter / setter

    }

    /p>

    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    select="com.howl.dao.CommentDao.selectCommentById" column="{blogId=blog_id,parentId=comment_id}"

    fetchType="lazy">

    SELECT comment_id,nickname,content,blog_id,parent_id FROM blog WHERE blog_id = #{blogId} AND parent_id = #{parentId}

    @Service

    public class CommentService {

    @Autowired

    CommentDao commentDao;

    public List selectCommentById(int blogId) {

    // 默认传入-1,即找出父级评论先

    return commentDao.selectCommentById(blogId, -1);

    }

    }

    这样查询出来的语句是层层套的,不信你看

    [{

    "id": 1,

    "nickname": "小二",

    "content": "不错",

    "children": [{

    "id": 2,

    "nickname": "小三",

    "content": "支持",

    "children": [{

    "id": 3,

    "nickname": "小四",

    "content": "6666",

    "children": []

    }]

    }]

    }, {

    "id": 4,

    "nickname": "小五",

    "content": "一般般把",

    "children": []

    }]

    4. 两层型

    即只有两层关系,比单层多了互动功能,比套娃简洁,看图

    c9d16290dd61e757e3213a436d9c022d.png

    这种看起来舒服多了,怎么做到的呢? 其实和套娃型使用的是同一个表与查询,映射文件都不用改,不同之处在于查询出来的后期的逻辑处理,很多时候跨库也是如此,查完数据再进行逻辑的处理

    处理逻辑

    由套娃型转变成二层型

    套娃的示意图:

    ab40a9c354c3887bc94f957ee8c4895e.png

    1楼和2楼同级,属于父级评论,直接挂载的博客下

    A属于1楼评论的子级

    B属于A的子级

    C属于B的子级

    二层的示意图:

    4df4a88fd6f98451a30116562a464e55.png

    A,B,C 属于同级,直接属于1楼评论的子级

    处理逻辑代码

    业务逻辑在Service层,DTT测试

    @RunWith(SpringJUnit4ClassRunner.class)

    @ContextConfiguration(locations = "classpath:applicationContext.xml")

    public class CommentServiceTest {

    @Autowired

    CommentDao commentDao;

    @Test

    public void selectCommentById() {

    // 默认传入-1,找出父级的评论,假装查看博客id为7的评论

    List comments = commentDao.selectCommentById(7, -1);

    // 这里将套娃关系处理为二层关系

    System.out.println(JSON.toJSONString(findParent(comments)));

    }

    // 处理每个父级评论的子级及其嵌套子级

    public List findParent(List comments) {

    for (CommentDTO comment : comments) {

    // 防止checkForComodification(),而建立一个新集合

    ArrayList fatherChildren = new ArrayList<>();

    // 递归处理子级的回复,即回复内有回复

    findChildren(comment, fatherChildren);

    // 将递归处理后的集合放回父级的孩子中

    comment.setChildren(fatherChildren);

    }

    return comments;

    }

    public void findChildren(CommentDTO parent, List fatherChildren) {

    // 找出直接子级

    List comments = parent.getChildren();

    // 遍历直接子级的子级

    for (CommentDTO comment : comments) {

    // 若非空,则还有子级,递归

    if (!comment.getChildren().isEmpty()) {

    findChildren(comment, fatherChildren);

    }

    // 已经到了最底层的嵌套关系,将该回复放入新建立的集合

    fatherChildren.add(comment);

    // 容易忽略的地方:将相对底层的子级放入新建立的集合之后

    // 则表示解除了嵌套关系,对应的其父级的子级应该设为空

    comment.setChildren(new ArrayList<>());

    }

    }

    }

    注释清楚地说明了处理逻辑,但这种做法显然不是很好的,可以有更优雅的处理方法,只是笔者还没想到

    输出结果

    [{

    "id": 1,

    "nickname": "小二",

    "content": "不错",

    "children": [{

    "id": 3,

    "nickname": "小四",

    "content": "6666",

    "children": []

    }, {

    "id": 2,

    "nickname": "小三",

    "content": "支持",

    "children": []

    }]

    }, {

    "id": 4,

    "nickname": "小五",

    "content": "一般般把",

    "children": []

    }]

    后记:后期逻辑处理部分花了大半天没滤清关系,没想到第二天醒来随手两分钟就搞定。原因:增强for底层使用了迭代器,修改结构会有快速失败机制、还有处理二层关系的时候,最底层往上解除套娃关系时,记得将孩子置空

    b739ec46bb5c46d9c0aa4ce35ba1ea56.png

    关于找一找教程网

    本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

    本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

    [评论功能的简单实现]http://www.zyiz.net/tech/detail-115177.html

    展开全文
  • Java实现评论回复功能的完整步骤

    千次阅读 2021-02-12 21:25:46
    前言使用递归循环开发评论回复功能,适用于大部分的简单单体应用评论功能或许是大多数的单体应用之中会用到的功能,我们会在自己所开发的项目之中进行集成该功能大多数时候我们会将评论功能划分成以下几种:单一型嵌...

    前言

    使用递归循环开发评论回复功能,适用于大部分的简单单体应用

    评论功能或许是大多数的单体应用之中会用到的功能,我们会在自己所开发的项目之中进行集成该功能

    大多数时候我们会将评论功能划分成以下几种:

    单一型

    嵌套型

    两层型

    一、分类方式

    1、单一型

    单一型评论方式就是日常论坛之中的盖楼的方式

    用户只能根据所在的文章或者问题进行单一回复,评论之间没有互动

    类似于问答形式。提出问题,然后回答,一对多关系。这些回答之间没有任何联系

    03a8ad7122766876b6fcf58c1fc42201.png

    2、嵌套型

    嵌套型评论方式会对有回复的评论进行递归,会造成后端性能不佳,而且对于前端的展示也不是很友好

    dc89aa3cf722819662150dfc2a680975.png

    3、两层型

    两层型评论方式就是除了一级评论之外,无论是对于该评论的回复还是对于回复的回复都统一在第二层

    db5c07092ded3fea6ec5a960a2161460.png

    二、实现原理

    就以最常见的博客来说,不同的分类方式实现原理不一样

    1、单一型

    我们只需要在评论的数据表格中添加博客id即可,查询出相对应的数据直接进行展示即可

    create table `comment` (

    `id` int(11) not null auto_increment comment '主键id',

    `nickname` varchar(255) default null comment '评论者昵称',

    `avatar` varchar(255) comment '评论头像',

    `content` varchar(255) default null comment '评论的内容',

    `blog_id` int(11) default null comment '评论的博客id',

    primary key (`id`)

    ) comment '评论表';

    在业务之中根据博客id查询出来,传递给前端展示出来即可

    select * from comment where blog_id=#{blog_id}

    2、嵌套型

    嵌套型的评论方式所需要的数据结构是树状型的,评论多起来的话层级结构会变得很复杂,对于性能消耗也是很巨大,【不推荐】

    实现原理为我们会在评论表之中添加一个【parent_id】字段,定义评论和回复为父子级的关系,评论为父级,回复为子级,默认为【-1】,表示为没有父级,

    create table `comment` (

    `id` int(11) not null auto_increment comment '主键id',

    `nickname` varchar(255) default null comment '评论者昵称',

    `avatar` varchar(255) comment '评论头像',

    `content` varchar(255) default null comment '评论的内容',

    `blog_id` int(11) default null comment '评论的博客id',

    `parent_id` int(11) default '-1' comment '父级评论id',

    primary key (`id`)

    ) comment '评论表';

    需要使用递归和链表进行循环遍历插入回复

    设计如下:

    Content.java

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键id")

    @TableId(value = "id", type = IdType.ASSIGN_ID)

    private Integer id;

    @ApiModelProperty(value = "用户昵称")

    @TableField("nickname")

    private String nickname;

    @ApiModelProperty(value = "头像")

    @TableField("avatar")

    private String avatar;

    @ApiModelProperty(value = "评论")

    @TableField("comment")

    private String comment;

    @ApiModelProperty(value = "博客id ")

    @TableField("blog_id")

    private Integer blogId;

    @ApiModelProperty(value = "回复评论id")

    @TableField("parent_id")

    private Integer parentId;

    DTO设计

    ContentDTO.java

    @Data

    @NoArgsConstructor

    @AllArgsConstructor

    @Accessors(chain = true)

    @ApiModel(value = "评论模型")

    @JsonIgnoreProperties(value = { "handler" })

    public class ContentDTO {

    private int id;

    private String nickname;

    private String content;

    private List children;

    }

    使用mybatis做为持久层框架,编写sql查询语句进行嵌套查询,

    select="com.zukxu.items.comment.mapper.ContentMapper.selectCommentById" column="{blogId=blog_id,parentId=comment_id}"

    fetchType="lazy">

    SELECT comment_id,nickname,content,blog_id,parent_id FROM blog WHERE blog_id = #{blogId} AND parent_id = #{parentId}

    结果如下:

    [

    {

    "id": "1309302063977304065",

    "nickname": "1",

    "content": "这次该可以了吧",

    "children": [

    {

    "id": "1309319425866698753",

    "nickname": "1",

    "content": "好了?",

    "children": []

    }

    ]

    },

    {

    "id": "1309341283121154994",

    "nickname": "4",

    "content": "为什么呢",

    "children": [

    {

    "id": "1309373849414787073",

    "nickname": "1",

    "content": "好了?",

    "children": []

    },

    {

    "id": "1309308402422091778",

    "nickname": "1",

    "content": "可以了吧",

    "children": []

    },

    {

    "id": "1309373675783184385",

    "nickname": "1",

    "content": "好了?",

    "children": [

    {

    "id": "1309373886580514817",

    "nickname": "1",

    "content": "???",

    "children": []

    }

    ]

    }

    ]

    }

    ]

    结果会造成多重嵌套,不是很友好

    3、两层型

    比单一型多了互动的功能,比嵌套型更加简洁,方便操作管理

    设计和嵌套型保持一致,只需要在查询出来数据之后对数据进行处理即可

    将嵌套型转为两层型结构

    处理每个父级评论的子级及其嵌套子级

    public List findParent(List comments) {

    for (CommentDTO comment : comments) {

    // 防止checkForComodification(),而建立一个新集合

    ArrayList fatherChildren = new ArrayList<>();

    // 递归处理子级的回复,即回复内有回复

    findChildren(comment, fatherChildren);

    // 将递归处理后的集合放回父级的孩子中

    comment.setChildren(fatherChildren);

    }

    return comments;

    }

    public void findChildren(CommentDTO parent, List fatherChildren) {

    // 找出直接子级

    List comments = parent.getChildren();

    // 遍历直接子级的子级

    for (CommentDTO comment : comments) {

    // 若非空,则还有子级,递归

    if (!comment.getChildren().isEmpty()) {

    findChildren(comment, fatherChildren);

    }

    // 已经到了最底层的嵌套关系,将该回复放入新建立的集合

    fatherChildren.add(comment);

    // 容易忽略的地方:将相对底层的子级放入新建立的集合之后

    // 则表示解除了嵌套关系,对应的其父级的子级应该设为空

    comment.setChildren(new ArrayList<>());

    }

    }

    }

    最后的结果如下:

    [

    {

    "id": "1309302063977304065",

    "userId": "1",

    "comment": "这次该可以了吧",

    "children": [

    {

    "id": "1309319425866698753",

    "userId": "1",

    "comment": "好了?",

    "children": []

    }

    ]

    },

    {

    "id": "1309341283121154994",

    "userId": "4",

    "comment": "为什么呢",

    "children": [

    {

    "id": "1309373849414787073",

    "userId": "1",

    "comment": "好了?",

    "children": []

    },

    {

    "id": "1309308402422091778",

    "userId": "1",

    "comment": "可以了吧",

    "children": []

    },

    {

    "id": "1309373886580514817",

    "userId": "1",

    "comment": "???",

    "children": []

    },

    {

    "id": "1309373675783184385",

    "userId": "1",

    "comment": "好了?",

    "children": []

    }

    ]

    }

    ]

    绝大多数时候我们都会去使用两层型的评论方式做评论

    总结

    到此这篇关于Java实现评论回复功能的文章就介绍到这了,更多相关Java实现评论回复功能内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    展开全文
  • 留言板:简单的留言功能实现

    千次阅读 2020-12-26 16:55:15
    记录学习的第一阶段 ...我决定要用自己的想法来实现留言板这个...(网上留言板编写教程很多,建议还是先靠自己的想法来实现)虽然这个案例实现功能不多,但是编写的过程还是遇到了挺多的问题,特别是接口的编写。 ...

    记录学习的第一阶段

    自从我开始学习Web一个月以来,照着视频课程写过不少的练习,所以当我粗略的学习了Web三件套和php+Mysql后。我决定要用自己的想法来实现留言板这个练习,来巩固自己的学习。毕竟纸上得来终觉浅,绝知此事要躬行,实践才是最好的老师。(网上留言板编写教程很多,建议还是先靠自己的想法来实现)虽然这个案例实现的功能不多,但是编写的过程还是遇到了挺多的问题,特别是接口的编写。(第一次写接口的时候真的是特别懵)。在这里也很感谢我同学对我的指引,让我在学习的路少走了很多弯路,感谢感谢感谢~。本来想把功能完善的更好一点(因为急着进入下一阶段的学习,所以实现了简单的留言功能之后就停下来了,以后一定回头把它完善好)

    • 功能实现
      1. 提交留言,通过php把留言写入Mysql数据库,再通过AJAX从数据库查询最后一条留言显示出来实现局部刷新。
      1. 页面初始化,通过php查询Mysql数据库里的留言,全部显示出来。
      1. 心动画的实现(心会跳动)

    效果图:
    留言板
    html代码:

    <!DOCTYPE html>
    <html lang="en">
        <style>
            div#dem p{
             
             margin-top: 10px;
             margin-bottom: 10px;
             font-size: 24px;
             }
             
            
        </style>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="lyb.css?v=12">
        <script>//按钮按下执行的脚本
            function newmessage(){
            var x =document.getElementById("srname").value;
            var y =document.getElementById("srmessage").value;
            if(x==""){
               alert("必须填写姓名!");
               return false;
            }
            else if (y == "") {
               alert("必须填写留言!");
               return false;
             }
             else{
                document.getElementById("srname").value="";//提交以后清空内容
                document.getElementById("srmessage").value="";//提交以后清空内容
               var xhttp = new XMLHttpRequest();
               xhttp.onreadystatechange=function(){
                    if(this.readyState==4&&this.status==200){     //先向数据库添加数据,当服务器响应则查询最后一个留言
                        var xhttp = new XMLHttpRequest();{
                        xhttp.onreadystatechange = function() {
                        if (this.readyState == 4 && this.status == 200) { //向服务器响应则查询最后一个留言
                        var box=document.getElementById("dem");
                        var str=this.responseText;
                        var strArray=str.split("}{");//以}{分割字段
                        for(var i=0;i<strArray.length;i++){
                            if(i=strArray.length-1){
                            strArray[i]=strArray[i].replace("{","");//去掉字符串里的某个字符
                            strArray[i]=strArray[i].replace("}","");
                            var str=strArray[i];
                            var obj=document.createElement("p");
                            obj.innerText=str;
                            document.getElementById("dem").appendChild(obj);
                                                }
                                        }
                                    }               
                                }
                        };
                            xhttp.open("post", "/chaxun.php", true);//向数据库添加数据请求
                            xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");//加了这个就可以以表单方式提交,以头文件形式?
                            xhttp.send(); 
                    }
           }
                            xhttp.open("POST", "/xxx.php", true);
                            xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");//加了这个就可以以表单方式提交,以头文件形式?
                            xhttp.send(JSON.stringify({
                            "name" :x,
                            "message" :y
                             }));
                             $("#name").val(""); 
           
            }
        }
       </script>
       <script>         //界面初始化执行脚本,查询留言并显示出来。
           window.onload=function(){
           var xhttp = new XMLHttpRequest();{
           xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var box=document.getElementById("dem");
                var str=this.responseText;
                var strArray=str.split("}{");//以}{分割字段
                    for(var i=0;i<strArray.length;i++){
                            strArray[i]=strArray[i].replace("{","");//去掉字符串里的某个字符
                            strArray[i]=strArray[i].replace("}","");
                            var str=strArray[i];
                            var obj=document.createElement("p");
                            obj.innerText=str;
                            document.getElementById("dem").appendChild(obj);
                        
                }
              }               
           }
        };
            xhttp.open("post", "/chaxun.php", true);
            xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");//加了这个就可以以表单方式提交,以头文件形式?
            xhttp.send(); 
        
    } 
        
       </script>
    </head>
    <body>
        <div id="body">
        <header>
            
           
            <p class="headerP">十三毕业留言</p>
            <button class="dl">管理员登录</button>
            
        </header>
            <input id="srname" class="inputname" type="text" name="name" placeholder="请输入你的姓名(必填)">
            <textarea id="srmessage" class="inputtextarea" name="newmessage" placeholder="请输入你想写的留言(必填)"></textarea>
            <button  class="buttontj" onclick="newmessage()">提交留言</button>
             <span class="heart"><!--用来设置心形动画的实现-->
                <span class="heart-left"></span><span class="heart-right"></span>
            </span>
            <div id="dem"></div>
       </div>
       
        
    </body>
    </html>
    

    css样式:

    *{ margin: 0;padding: 0;}
    p.headerP{
        line-height: 50px;
        display: inline-block;
        color: white;
        margin-left:10px;
        font-size: 18px;
    }
    div#body{
        margin-left: 20%;
        margin-right: 20%;
    }
    body{
        background:url(picture/320539.jpg);
        background-size: 1920px 1080px;
        background-repeat:repeat-y;
        position: relative;
        
    }
    header{
        height: 50px;
        background-color: #32393F;
        margin-bottom: 10px;
         display: flex;
         justify-content: space-between;
         border-radius: 6px;
         margin-top: 16px;
         
    }
    button.dl{
          width:100px ;
          text-align: center;
          background-color:#4facfe;
          font-size: 16px;
          color: white;
          border-radius: 13px;    
          height: 40px;
          margin-top: 5px;
          margin-right: 5px;
          border: white;
    }
    input.inputname{
        height: 30px;
        width:99.8%;
        font-size: 18px;
        border-radius: 10px;
        outline: none;
        border: white;
        
    }
    textarea.inputtextarea{
        width: 100%;
        height: 120px;
        font-size: 22px;
        margin-top: 10px;
        border-radius: 13px;
        outline: none;
        border: white;
    }
    button.buttontj{
        width: 100%;
        height: 40px;
        border: white;
        background-color: #027BFE;
        border-radius: 18px;
        color: white;
        font-size: 20px;
        margin-top: 10px;
        margin-bottom: 12px;
    }
    
    
    span{
        display: inline-block;
        
    }
    .heart-left,.heart-right{    /*画出基本样式*/
        width: 25px;height: 40px;
        background-color: red;
        border-top-left-radius: 20px;
        border-top-right-radius: 20px;
     }
     .heart-left{  /*通过旋转变为心形*/
         transform: rotateZ(-45deg);
     }
     .heart-right{  /*通过旋转变为心形*/
         transform: translateX(-14px) rotateZ(45deg);
     }
     @keyframes xin{
         30%{transform: scale(1.3);}
         100%{transform: scale(1);}
     }
     .heart{
         animation: xin 1.5s infinite;
         margin-left: 10px;
     }
    
    

    php程序:

    <html>
    <body>
    <?php 
    $a=file_get_contents ( 'php://input' );
    $link=mysqli_connect("localhost","root","123456");
    $db_selectd=mysqli_select_db($link,"lzm");
    $query="insert into t1(info) values('$a')";
    mysqli_query($link,$query);
    ?>
    </body>
    </html>
    
    <?php 
    $link=mysqli_connect("localhost","root","123456");
    $db_selectd=mysqli_select_db($link,"lzm");
    $query="select*from t1 order by into desc limit 1";
    var_dump(mysqli_query($link,$query));
    
    ?>
    

    代码全部在这里了,喜欢的点赞关注码走吧。(其中或多或少可能会有一点bug,新人勿喷)

    展开全文
  • AI五子棋第一篇-利用最简单的C语言实现

    千次阅读 多人点赞 2021-07-28 16:28:51
    如何实现 1.说明:由于本文只是对初学C语言的人学习,所以将不会涉及任何算法,电脑将采用随机下子的方式。(后期会为大家介绍Alpha-Beta剪枝算法实现人工智能AI) 2.主要部分: (1)菜单 (2)打印棋盘 (3)玩家...

    一.如何实现

    1.说明:由于本文只是对初学C语言的人学习,所以将不会涉及任何算法,电脑将采用随机下子的方式。(后期会为大家介绍Alpha-Beta剪枝算法实现人工智能AI)
    2.主要部分:
    (1)菜单
    (2)打印棋盘
    (3)玩家下子
    (4)电脑下子
    (5)判断输赢

    二.实现代码及分析

    (1)菜单的制作
    在这里插入图片描述
    在这里插入图片描述
    运用do…while循环调用菜单,根据用户选择实现玩游戏和退出游戏

    (2)棋盘的初始化和打印
    棋盘采用标准的15*15的格子,我们可以宏定义ROW和COL分别为15和15来表示行和列。
    在这里插入图片描述
    分别封装两个函数对棋盘进行初始化和打印
    初始化:(这里将棋盘初始化为空格,可初始化为其他)
    在这里插入图片描述
    打印棋盘:

    在这里插入图片描述
    效果如下:
    在这里插入图片描述
    (3)玩家下子

    void PlayerMove(char board[ROW][COL], int row, int col) {
    	int x, y;
    	while (1) {
    		printf("玩家走:\n");
    		printf("请输入坐标:\n");
    		scanf("%d %d", &x, &y);
    		if (x >= 1 && x <= row && y >= 1 && y <= col) {
    			if (board[x - 1][y - 1] == ' ') {
    				board[x - 1][y - 1] = 'O';
    				break;
    			}
    			else {
    				printf("坐标被占用,请重新输入\n");
    			}
    		}
    		else {
    			printf("坐标非法,请重新输入\n");
    		}
    	}
    }
    

    玩家下子主要采用的思路是,判断棋盘上是否有子,已经输入的坐标是否合法。
    (4)电脑下子

    void ComputerMove(char board[ROW][COL], int row, int col) {
    	int x, y;
    	printf("电脑走\n");
    	while (1) {
    		x = rand() % row;
    		y = rand() % col;
    		if (board[x][y] == ' ') {
    			board[x][y] = 'X';
    			break;
    		}
    	}
    }
    

    与玩家下子相同,此处采用的随机下子,后期可进行优化(比如:极大极小值算法、Alpha-Beta剪枝算法等)

    (5)判断输赢
    通过遍历整个棋盘,观察是否有连五子情况出现,代码如下:

    char iswin(char board[ROW][COL], int row, int col) {
    	//行
    	int ren=0,dian=0,i,j;
    	for (i = 0;i < row;i++) {
    		ren = 0;
    		for (j = 0;j < col;j++) {
    			if (board[i][j] == 'O')
    				ren++;
    			else
    				ren = 0;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	for (i = 0;i < row;i++) {
    		dian = 0;
    		for (j = 0;j < col;j++) {
    			if (board[i][j] == 'X')
    				dian++;
    			else
    				dian = 0;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//列
    	ren = dian = 0;
    	for (i = 0;i < row;i++) {
    		ren = 0;
    		for (j = 0;j < col;j++) {
    			if (board[j][i] == 'O')
    				ren++;
    			else
    				ren = 0;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	for (i = 0;i < row;i++) {
    		dian = 0;
    		for (j = 0;j < col;j++) {
    			if (board[j][i] == 'X')
    				dian++;
    			else
    				dian = 0;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//右下
    	ren = dian =i=j= 0;
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = 0;
    		ren = 0;
    		while (i < row && j < col) {
    			if (board[i][j] == 'O') {
    				ren++;
    			}
    			else {
    				ren = 0;
    			}
    			i++;
    			j++;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	i = j = 0;
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i < row && j < col) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j++;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//右上
    	for (int k = row;k >=0;k--) {
    		j = col;
    		i = k;
    		ren = 0;
    		while (i >=0 && j >=0) {
    			if (board[i][j] == 'O') {
    				ren++;
    			}
    			else
    				ren = 0;
    			i--;
    			j--;
    			if (ren >= 5)
    				return 'o';
    		}
    
    	}
    	
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i >= 0 && j >= 0) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j--;
    			if (dian >= 5)
    				return 'o';
    		}
    		
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i < row && j >= 0) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = 0;k <row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i <row && j >= 0) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i < row && j >= 0) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = 0;k <row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i <row && j >= 0) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	return 'c';
    	//左
    }
    

    三.整个代码

    (1)test.c文件下代码:

    #define _CRT_SECURE_NO_WARNINGS 1
    #include"game.h"
    void menu() {
    	printf("**************************\n");
    	printf("******* 1. play  *********\n");
    	printf("******* 0. exit  *********\n");
    	printf("**************************\n");
    }
    void game() {
    	//棋盘数组
    	char board[ROW][COL],ret;
    	//初始化棋盘
    	InitBoard(board, ROW, COL);
    	//打印棋盘
    	PrintBoard(board, ROW, COL);
    	//下棋
    	int a;
    	printf("1.先手 0.后手");
    	scanf("%d", &a);
    	if(a==1)
    		PlayerMove(board, ROW, COL);
    	else
    		ComputerMove(board, ROW, COL);
    	while (1) {
    		if (a == 0) {
    			//PlayerMove(board, ROW, COL);
    			PlayerMove(board, ROW, COL);
    			PrintBoard(board, ROW, COL);
    			ret=iswin(board, ROW, COL);
    			if (ret != 'c') {
    				break;
    			}
    			//ComputerMove(board, ROW, COL);
    			ComputerMove(board, ROW, COL);
    			PrintBoard(board, ROW, COL);
    			ret = iswin(board, ROW, COL);
    			if (ret != 'c') {
    				break;
    			}
    		}
    		else {
    			//ComputerMove(board, ROW, COL);
    			ComputerMove(board, ROW, COL);
    			PrintBoard(board, ROW, COL);
    			ret = iswin(board, ROW, COL);
    			if (ret != 'c') {
    				break;
    			}
    			//PlayerMove(board, ROW, COL);
    			PlayerMove(board, ROW, COL);
    			PrintBoard(board, ROW, COL);
    			ret = iswin(board, ROW, COL);
    			if (ret != 'c') {
    				break;
    			}
    		}
    	}
    	if (ret == 'o')
    		printf("玩家赢\n");
    	else if (ret == 'x')
    		printf("电脑赢\n");
    	else
    		printf("平局\n");
    }
    int main() {
    	int input;
    	srand((unsigned int)time(NULL));
    	do {
    		menu();
    		scanf("%d", &input);
    		switch (input) {
    		case 1:
    			game();
    			break;
    		case 0:
    			printf("退出游戏\n");
    			break;
    		default:
    			printf("选择错误\n");
    			break;
    		}
    	} while (input);
    	return 0;
    }
    

    (2)game.c下的代码

    #define _CRT_SECURE_NO_WARNINGS 1
    #include"game.h"
    void InitBoard(char board[ROW][COL], int row, int col) {
    	for (int i = 0;i < row;i++) {
    		for (int j = 0;j < col;j++) {
    			board[i][j] = ' ';
    		}
    	}
    }
    void PrintBoard(char board[ROW][COL], int row, int col) {
    	for (int i = 0;i < row;i++) {
    		printf("  ");
    		printf("%2d", i+1);
    	}
    	printf("\n");
    	for (int i = 0;i < row;i++) {
    		//打印数据
    		printf("%2d", i + 1);
    		for (int j = 0;j < col;j++) {
    			printf(" %c ", board[i][j]);
    			if (j < col - 1)
    				printf("|");
    		}
    		printf("\n");
    		//打印分割行
    		if (i < row - 1) {
    			printf("  ");
    			for (int j = 0;j < col;j++) {
    
    				printf("---");
    				if (j < col-1)
    					printf("|");
    			}
    			printf("\n");
    		}
    	}
    }
    
    void PlayerMove(char board[ROW][COL], int row, int col) {
    	int x, y;
    	while (1) {
    		printf("玩家走:\n");
    		printf("请输入坐标:\n");
    		scanf("%d %d", &x, &y);
    		if (x >= 1 && x <= row && y >= 1 && y <= col) {
    			if (board[x - 1][y - 1] == ' ') {
    				board[x - 1][y - 1] = 'O';
    				break;
    			}
    			else {
    				printf("坐标被占用,请重新输入\n");
    			}
    		}
    		else {
    			printf("坐标非法,请重新输入\n");
    		}
    	}
    }
    
    void ComputerMove(char board[ROW][COL], int row, int col) {
    	int x, y;
    	printf("电脑走\n");
    	while (1) {
    		x = rand() % row;
    		y = rand() % col;
    		if (board[x][y] == ' ') {
    			board[x][y] = 'X';
    			break;
    		}
    	}
    }
    
    char iswin(char board[ROW][COL], int row, int col) {
    	//行
    	int ren=0,dian=0,i,j;
    	for (i = 0;i < row;i++) {
    		ren = 0;
    		for (j = 0;j < col;j++) {
    			if (board[i][j] == 'O')
    				ren++;
    			else
    				ren = 0;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	for (i = 0;i < row;i++) {
    		dian = 0;
    		for (j = 0;j < col;j++) {
    			if (board[i][j] == 'X')
    				dian++;
    			else
    				dian = 0;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//列
    	ren = dian = 0;
    	for (i = 0;i < row;i++) {
    		ren = 0;
    		for (j = 0;j < col;j++) {
    			if (board[j][i] == 'O')
    				ren++;
    			else
    				ren = 0;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	for (i = 0;i < row;i++) {
    		dian = 0;
    		for (j = 0;j < col;j++) {
    			if (board[j][i] == 'X')
    				dian++;
    			else
    				dian = 0;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//右下
    	ren = dian =i=j= 0;
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = 0;
    		ren = 0;
    		while (i < row && j < col) {
    			if (board[i][j] == 'O') {
    				ren++;
    			}
    			else {
    				ren = 0;
    			}
    			i++;
    			j++;
    			if (ren >= 5)
    				return 'o';
    		}
    		
    	}
    	i = j = 0;
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i < row && j < col) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j++;
    			if (dian >= 5)
    				return 'x';
    		}
    		
    	}
    	//右上
    	for (int k = row;k >=0;k--) {
    		j = col;
    		i = k;
    		ren = 0;
    		while (i >=0 && j >=0) {
    			if (board[i][j] == 'O') {
    				ren++;
    			}
    			else
    				ren = 0;
    			i--;
    			j--;
    			if (ren >= 5)
    				return 'o';
    		}
    
    	}
    	
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i >= 0 && j >= 0) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j--;
    			if (dian >= 5)
    				return 'o';
    		}
    		
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = row;k >= 0;k--) {
    		i = k;
    		j = 0;
    		dian = 0;
    		while (i >= 0 && j <col) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i--;
    			j++;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	for (int k = 0;k < row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i < row && j >= 0) {
    			if (board[i][j] == 'O') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'o';
    		}
    
    	}
    	for (int k = 0;k <row;k++) {
    		i = k;
    		j = col;
    		dian = 0;
    		while (i <row && j >= 0) {
    			if (board[i][j] == 'X') {
    				dian++;
    			}
    			else
    				dian = 0;
    			i++;
    			j--;
    			if (dian >= 5)
    				return 'x';
    		}
    
    	}
    	return 'c';
    	//左
    }
    

    (3)game.h下的代码

    #pragma once
    #define ROW 15
    #define COL 15
    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    //初始化棋盘
    void InitBoard(char board[ROW][COL], int row, int col);
    //打印棋盘
    void PrintBoard(char board[ROW][COL], int row, int col);
    //人走
    void PlayerMove(char board[ROW][COL], int row, int col);
    //电脑走
    void ComputerMove(char board[ROW][COL], int row, int col);
    //判断输赢
    char iswin(char board[ROW][COL], int row, int col);
    
    

    四.具体效果

    1.棋盘打印以及选择先后手
    在这里插入图片描述
    2.玩家和电脑下子
    在这里插入图片描述
    3.判断输赢
    在这里插入图片描述
    此处我们看到玩家赢了,可是电脑实在太蠢了,所以还有很多地方需要添加的
    下一篇:链接: 极大极小值算法实现AI功能.

    欢迎各位大佬对此代码进行优化!

    展开全文
  • 最简单的方法:实现QWidget窗体的鼠标移动功能 应用场景 自定义QWidget派生类 用鼠标来移动窗体 方法 继承QWidget类 重写mousePressEvent()、mouseMoveEvent()方法 使用QPoint成员变量来保存鼠标按下时...
  • 1.业务需求 为什么要使用微信的模板消息推送,最近有个需求是将消息推送到微信公众号,之前的系统已经支持邮箱和短信推送消息。 微信的模板消息推送就是我们在订阅某个公众号以后,进行支付等操作时,支付成功...
  • Android Studio仿QQ界面实现简单功能

    千次阅读 热门讨论 2021-06-02 09:45:03
    有任何关于代码和表述问题,欢迎评论区指出 楼主近期在学习关于安卓中Fragment和ListView中的知识,按照老师的要求模仿一下QQ界面 要求功能 有登录界面 密码不对提示密码不对 账号密码任一为空提示用户不能为空 ...
  • 有必要用一下php+mysql实现一下这个“基础”的用户功能,(虽然开发可能会用后端云) 基础结构 html+css+JavaScript作前端渲染; php作为后端,mysql作为数据库。 在这里暂时不涉及到安全问题(比如验证码和token...
  • 实现代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> form .text { display: inline-block...
  • 简单的点餐系统实现

    千次阅读 2020-12-28 20:16:29
    二、实现功能 外卖订餐系统 具体要求如下: 使用选择结构,循环结构,数组的知识实现一个外卖订餐系统 运行效果图如下: 1.订餐功能 2.查看餐袋 3.签收订单 4.删除订单 5.点赞 6.退出 代码如下 package waimai...
  • 第一步:建立简单的项目 第二步:建一个简单的数据表 第三步:配置文件如下: pom.xml文件配置: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=...
  • 下面笔者将使用Verilog HDL在Vivado上面实现74ls151的功能。 引脚 74ls151共14根引脚,具体如下: 使能端:共1根,低电平有效,输入使能信号。 地址段:共3根,通过组成二进制编码来进行0~7的编号,以对应8个不同的...
  • jsp实现简单的用户登录和注册

    千次阅读 2021-03-08 10:30:30
    用jsp实现一个简单的登录界面,主要是验证码具体要CSS布局HTML小编今天和大家分享如下: 一个用户名一个密码,还有一个验证码功能,用户名不是jq 简单页面 function yzm(){ var Num=""; for(var i=0;iweb JSP 简单的...
  • C 语言实现计算器(可视化界面和多功能

    千次阅读 多人点赞 2021-05-29 23:32:08
    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮...今天在电脑看到大一学C语言时,实验课上写的计算器功能,挺有意思。所以在此分享给学C语言的学弟学妹,有2种版本,记得收藏保留! 简单版本计算器 简单版本.
  • 前言 网上绝大多数博客都是发送端或者接收端同时作为服务器...但是Django 3.0往上走就不支持websocket了就很无语,所以这里我通过channels实现websocket。 1.WebSocket 在讲Websocket之前,先了解下 long poll 和...
  • 在项目的开发过程中,时间比较紧急,通过自定义的方式很显然需要耗费很多时间去写,所以我们需要使用更简单的方式实现,这样会帮我们节省很多时间去解决其它的问题,使用依赖库的方式显然是节省时间的,下面我们来...
  • 如何在SpringBoot启动时执行初始化操作,两个简单接口就可以实现
  • JAVA 实现简单的学生成绩管理系统

    千次阅读 2021-03-15 16:15:11
    2.掌握简单的信息管理系统的设计与实现。二、实验环境实验建议在安装了以下软件的计算机上完成:1.Windows xp/win7/win8/win10操作系统2.JDK 1.6以上版本3.Eclipse或NetBeans IDE或EditPlus或其它开发工具三、实验...
  • java 拼音搜索功能设计与实现

    千次阅读 2021-12-04 15:36:41
    本篇结合实际案例相信讲解了基于mysql如何实现中文的拼音检索功能
  • 搜索功能在各个项目中都很常见,在这篇文章中将通过大量的 custom hook 来实现这个搜索模块的功能
  • 用Excel也能实现和Python数据分析一样的功能! 这是一篇关于如何用excel做数据分析的案例。目的是帮助大家,在遇到小型数据样本时,快速利用excel做分析。所以本篇文章的重点是分析思路+数据处理+可视化的实现,...
  • Springboot实现简单的登录增删改查详细代码(idea)1、使用idea创建springboot项目1.1导入web依赖和lombok,还有thymeleaf支持1.2静态资源的引入1.3application.properties文件内容1.4国际化设置2、配置完成后开始...
  • C语言实现简单的四则运算计算器

    千次阅读 2021-04-01 14:59:01
    这是我学习C语言过程中的一个小练习,后续应该会对计算器进行功能添加和优化 本文主要介绍编程过程中遇到的问题、原因和解决办法 一、编程过程中遇到的错误 1.第二个scanf函数()不等输入就自动执行 2. 编译时报错...
  • 功能齐全的屏幕截图C++实现详解

    千次阅读 多人点赞 2021-11-07 21:36:58
    一个具有完备功能的屏幕截图应该包含以上多个功能点,比如桌面灰化、窗口自动套索、区域放大、矩形等多个图元绘制、输入文字等,本文将讲述屏幕截图实现的诸多细节。
  • 但是很多人可能忽略了一点,笔记本或者台式电脑同屏到电视或者投影仪的功能也特别强大,比如会议上使用到投影仪或者电视是很正常的,可是传统操作上各种连线,调试让会议人苦不堪言,这种落后且严重影响我们工作效率...
  • Python里,简单的人脸识别有很多种方法可以实现,依赖于python胶水语言的特性,我们通过调用包可以快速准确的达成这一目的。这里介绍的是准确性比较高的一种。 欲直接下载源代码文件,关注微信公众号:Python联盟,...
  • 单片机多级菜单的简单实现

    千次阅读 多人点赞 2021-03-25 18:02:55
    单片机多级菜单的简单实现 多级菜单的思路 最近想把stm32上的oled显示屏做的好看一些,于是动手写了写一个多级菜单,思路很简单,每个页面用单独的函数封装好,每个功能也是用单独的函数进行封装,用了3个按键,两个...
  • Linux网络编程-UDP实现QQ聊天功能

    千次阅读 2021-12-09 17:17:52
    目录 一、什么是UDP ...本博客是使用UDP单播实现QQ聊天功能,更多有关UDP单播介绍和和实现,可以查看博主文章:Linux网络编程-UDP单播服务客户端代码实现; 三、UDP实现QQ聊天功能 3.1 代码实现 由...
  • 【开发经验】redis实现抽奖功能

    千次阅读 2021-01-08 19:48:30
    抽奖的功能在互联网的项目中...但是这个功能说难也难,说简单简单。因为一般互联网的工程都是集群部署,抽奖的时候还要考虑线程间奖品争夺的问题,通过redis可以很轻松实现抽奖功能,我阐述下我的思路,请大家参考。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,219,566
精华内容 887,826
关键字:

最简单的评论功能怎么实现