第二次结对编程作业

第二次结对编程作业

1、链接

队友博客链接戳这里
本次作业博客链接戳这里
github项目地址

2、具体分工

  • 王景弘:负责实现AI部分,设计出牌算法,编写单元测试,提供算法思路、关键、改进和性能分析等博客内容。
  • 陈靖雯:负责实现UI部分,用接口连接算法形成最终文件,提供UI部分博客内容,用markdown格式编写博客内容。

3、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时
(分钟)
实际耗时
(分钟)
Planning 计划 30 30
· Estimate · 估计这个任务需要多少时间 30 30
Development 开发 4020 5195
· Analysis · 需求分析 (包括学习新技术) 600 1200
· Design · 生成设计文档 40 30
· Design Review · 设计复审 15 10
· Coding Standard · 代码规范 (为目前的开发制定或选择合适的规范) 5 5
· Design · 具体设计 40 40
· Coding · 具体编码 3000 3580
· Code Review · 代码复审 120 100
· Test · 测试(自我测试,修改代码,提交修改) 200 230
Reporting 报告 80 90
· Test Report · 测试报告 30 40
· Size Measurement · 计算工作量 20 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出改进计划 30 30
  · 合计 4130 5315

4、解题思路描述与设计实现说明

(1)网络接口的使用

按照所给的接口文档,调用所给接口。本次作业采用html、css、javascript实现UI部分,需要新建一个XMLHttpRequest对象,向所给地址发送GET或POST请求,需要在控制台观察是否响应以便修改错误。成功响应的请求会返回需要的内容。发送的数据用JSON.stringify()转换成json字符串发送,返回的json字符串用JSON.parse()转换为JS对象,再逐一匹配标签id显示到页面中或进行其他操作。由于用到Token认证,需要用cookie保存token值并加入到请求头中。

(2)代码组织与内部实现设计(类图)

第二次结对编程作业

(3)说明算法的关键与关键实现部分流程图

算法关键:

  • 实现的时候需要用到很多重复的switch和if/else语句。
  • 发到的牌按大小排完序之后,存入数组中,按照相同的牌的数量来分类。
  • 给每种牌型赋予权重值。
  • 利用switch语句不断的找到手牌中所有的牌型。
  • 之后将最大的拿出来留给后墩,然后剩下的牌再去寻找最大的牌型留给中墩,前墩的牌型就放在最后用剩下来的三张牌补进去,直到三道都有牌型。
  • 再把牌放到Choice.java中创建的三个数组中(即前中后墩)

关键实现部分流程图

第二次结对编程作业

5、关键代码解释

AI部分:
最开始发到牌后,将牌从小到大排序,存储到数组中。

	public void change(List<Card> handCard)
	{
	    Collections.sort(handCard,new Comparator<Card>()          //从小到大排序
		{
			public int compare(Card c1, Card c2) 
			{  
				int i = c1.rank - c2.rank;  
				if(i == 0)  
				    return c1.type - c2.type;    
				return i;
			}   
		});
	arrange(handCard);        //将牌整理到arr中

将排好序的牌按照相同的牌的数量来对数组进行分类

    for(int i=0;i<handCard.size();i++)
	{ 
		if((i+1)<handCard.size()&&handCard.get(i).rank==handCard.get(i+1).rank)
		if((i+2)<handCard.size()&&handCard.get(i).rank==handCard.get(i+2).rank)
		if((i+3)<handCard.size()&&handCard.get(i).rank==handCard.get(i+3).rank)    //四张相同的牌
		{
			arr.ranknum4.addAll(handCard.subList(i,i+4));
			i+=3;
		}
		else                                               //三张相同的牌
		{
			arr.ranknum3.addAll(handCard.subList(i,i+3));
		    i+=2;
		}
		else                                   //两张相同的牌
		{
			arr.ranknum2.addAll(handCard.subList(i,i+2));
			i+=1;
		}
		else                                  //没有相同的牌
		{
			arr.ranknum1.add(handCard.get(i));
		}
	}

通过判断读取出的对子数目和剩下的牌的数目来判断是否有牌型
此处为判断是否有四套三条和五对三条

    if(arr.ranknum3.size()==12||(arr.ranknum3.size()==9&&arr.ranknum4.size()==4))              //四套三条
	{
		choice=tochoice(handCard);
		choice.headType="sitaosantiao";
		return;
	}
	if(arr.ranknum2.size()==10&&arr.ranknum3.size()==3)       //五对三条
	{
		choice=tochoice(handCard);
		choice.headType="wuduisantiao";
		return;
	}

通过arr.ranknum4.size和arr.ranknum3.size的大小来判断牌型,并且改变Choice.java中的前中后墩数组(choice.headType/midType/endType)来进行出牌时的文字说明

	if(arr.ranknum4.size()==4)                  //尾道为铁支
	{
		choice.end.addAll(arr.ranknum4);
		card.removeAll(choice.end);
		arrange(card);
		if(arr.ranknum3.size()==6)              //中道是葫芦
		{
			if(!arr.ranknum2.isEmpty())
			{
				choice.mid.addAll(arr.ranknum3.subList(3, 6));
				choice.mid.addAll(arr.ranknum2);
				choice.midType="hulu";
				choice.head.addAll(arr.ranknum3.subList(0, 3));
				choice.headType="santiao";
				card.removeAll(choice.head);
				card.removeAll(choice.mid);
			    choice.end.addAll(card);
				choice.endType="tiezhi";
				return;
			}
			else
			{
				choice.mid.addAll(arr.ranknum3.subList(1, 6));
				card.removeAll(choice.mid);
				choice.end.add(card.get(0));
				choice.head.addAll(card.subList(1, 4));
				choice.endType="tiezhi";
				choice.midType="hulu";
				choice.headType="wulong";
				return;
			}
		}

UI部分:
登录的请求成功后会返回一个token,要用cookie保存,之后的请求要用split函数从cookie中提取出token放在其他需要token的请求的请求头中。

xhr.addEventListener("readystatechange", function () {
      if (this.readyState === this.DONE) {
      console.log(this.responseText);
      var JsonObj = JSON.parse(this.responseText);
      if(JsonObj.status==0)
      {
        document.cookie = JsonObj.data.token;
        valid();
      }
      }
      });
    var token = document.cookie.split(";")[0];
    xhr.setRequestHeader("x-auth-token",token);

进行下一次查询时需要删除之前表格中存在的数据,用到deleteRow函数将存在的行删除,若按从下标小到大的顺序删除,在删除过程中行的下标会不断改变,所以要从大到小删除。

    var tb = document.getElementById('table');
    var rowNum=tb.rows.length;
    for (var j=rowNum-1;j>=0;j--) //下标会变化,要从后往前删
    {
        tb.deleteRow(j);
    }

6、性能分析与改进

(1)描述改进思路

一开始只是单纯的想全用if/else语句来进行所有牌型的罗列但发现工程量实在是太大了,还是得逐步分析才能得到解法。后面想到先对花色和点数综合排序之后填入数组进行第一次分类(分点数大小的类),然后用判断数组大小的方式来进行第二次分类(分牌型的类,如对子三条之类的),再根据第二次分类出的结果来判断有没有特殊牌型(如全大全小、至尊青龙、五对三条之类的),最后给每种判断出的牌型赋予权重,用以判断什么牌型该放在什么位置。在进行完判断牌型的步骤之后再进行一下文字说明。

(2)展示性能分析图和程序中消耗最大的函数

第二次结对编程作业

7、单元测试

public static void main(String[] args) {
        List<Card> allCards = new ArrayList<>();
        Random random = new Random();
        CardController cardController = new CardController();
        for (int i = 1;i <= 4; i++){
            for (int j = 1; j <= 13; j++){
                allCards.add(new Card(j,i));
            }
        }

        for (int i = 0; i < 10; i++){
            List<Card> tempCards = new ArrayList<>();
            List<Card> cards = new ArrayList<>();
            tempCards.addAll(allCards);
            for (int j = 0; j < 13; j++){
                Card card = tempCards.get(random.nextInt(52 - j));
                cards.add(card);
                tempCards.remove(card);
            }
            String cardStr = "";
            for (int j = 0; j < 13; j++){
                Card card = cards.get(j);
                cardStr += card.toString();
                if (j < 12)
                    cardStr += " ";
            }
            JSONObject jsonObject = new JSONObject();
            try {
                jsonObject.put("id",0);
                jsonObject.put("card",cardStr);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            System.out.println(cardController.card2(jsonObject.toString()));;

        }
    }

每次随机构造13张牌,并且转化为符合json格式的字符串,再调用接口,得出结果

8、Github的代码签入记录

第二次结对编程作业
第二次结对编程作业

9、遇到的代码模块异常或结对困难及解决办法

(1)问题描述

UI部分:

  • 不熟悉如何将json数据显示在页面中。
  • 接口调用不知道如何实现。
  • http请求一直失败,显示未授权。

AI部分:

  • 因为刚开始接触java,关键的算法也是一筹莫展。
  • 在调用接口的时候也遇到了不会调接口,每个请求的写法不会,无数次请求失败。

(2)做过哪些尝试

UI部分:

  • 在百度等渠道疯狂搜索解决方法,查找之前练习的代码。
  • 询问同学。

AI部分:

  • 接口和java算法的问题都是老老实实看资料学习

(3)是否解决

UI部分:
已解决。(以下每一点与问题一一对应)

  • 正确使用javascript,理清标签父子关系,使用json.parse()将json格式转化成js对象。
  • 接口文档有code generation,根据需要修改。
  • token值没有保存,设置的请求头有错,使用了document.cookie解决。

AI部分:

  • 已解决。

(4)有何收获吐槽时刻

在这次作业,我负责UI部分,用了html、css、JavaScript实现。之前学过一点点理论,实现静态界面没有太大难度,几个界面完成后,对这部分内容更熟悉了一些。但是数据的动态显示花了很多时间,尤其是要调用所给的接口文档,屡屡请求失败,查找了各种报错的原因,试了n种解决办法,最后发现是放在请求头的token根本没有值(心塞塞)。。。后来使用了cookie成功解决。最大收获是知道了token认证,学会了调用接口,熟悉了前端和后端的配合。


10、评价你的队友

(1)值得学习的地方

  • 精通福建十三水
  • 克服了本次作业算法的困难
  • 学习能力强,提供的ai部分博客内容很赞

(2)需要改进的地方

  • 多一些细心就更好了,还有表达算法思路时过于纠结了哈哈哈

11、学习进度条

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
0 0 0 18 18 博客、github注册、markdown排版、博客css修改
1 325 325 41 59 java入门、性能分析、单元测试、覆盖率、github使用
2 0 325 18 77 学会原型设计工具,完成一次原型设计
3 0 325 0 77
4 2118 2443 20 97 二进制文件学习、ajax学习、html和css和js编写
5 292 2735 18 115 界面完善、接口学习和使用、token学习、二进制文件制作

制作UI时查找到的实用资料

HTML页面跳转的5种方法
用js实现动态添加表格数据
JSON.parse()
js中设置元素class的三种方法小结
js中删除table里所有行
详细介绍NW.js基本使用
HTML网页打包成EXE可执行文件
将Token添加到请求头Header中
JSON.parse() 与 JSON.stringify() 简单使用
Session与Token认证机制 前后端分离下如何登录
js使用sessionStorage、cookie保存token

**UI展示戳这里 **