2020年春季学期

计算机学院《软件构造》课程

Lab2实验报告

·· 1
3.1 Poetic Walks· 1
3.1.1 Get the code and prepare Git repository· 1
3.1.2 Problem 1: Test Graph · 2
3.1.3 Problem 2: Implement Graph · 3
3.1.3.1 Implement ConcreteEdgesGraph· 3
3.1.3.2 Implement ConcreteVerticesGraph· 5
3.1.4 Problem 3: Implement generic Graph· 7
3.1.4.1 Make the implementations generic· 7
3.1.4.2 Implement Graph.empty()· 7
3.1.5 Problem 4: Poetic walks· 7
3.1.5.1 Test GraphPoet· 7
3.1.5.2 Implement GraphPoet· 8
3.1.5.3 Graph poetry slam·· 9
3.1.6 Before you’re done· 9
3.2 Re-implement the Social Network in Lab1· 10
3.2.1 FriendshipGraph类··· 10
3.2.2 Person类··· 11
3.2.3 客户端main()· 11
3.2.4 测试用例··· 11
3.2.5 提交至Git仓库··· 12
3.3 Playing Chess· 12
3.3.1 ADT设计/实现方案··· 12
3.3.2 主程序MyChessAndGoGame设计/实现方案··· 16
3.3.3 ADT和主程序的测试方案··· 22
4 实验进度记录··· 24
5 实验过程中遇到的困难与解决途径··· 25
6 实验过程中收获的经验、教训、感想··· 25
6.1 实验过程中收获的经验和教训··· 25
6.2 针对以下方面的感受··· 26

1 实验目标概述

针对给定的应用问题,从问题描述中识别所需的 ADT;

设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;

根据 ADT 的规约设计测试用例;

ADT 的泛型化;

根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示 (representation)、表示不变性(rep invariant)、抽象过程(abstraction function)

使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表 示泄露(rep exposure);

测试 ADT 的实现并评估测试的覆盖度;

使用 ADT 及其实现,为应用问题开发程序;

在测试代码中,能够写出 testing strategy 并据此设计测试用例。。

2 实验环境配置

Eclipse,JDK8,Git,Junit4

GitHub Lab2仓库的URL地址

https://github.com/ComputerScienceHIT/Lab2-1180300412.git

3 实验过程

3.1 Poetic
Walks

对给定的接口Graph,完成两个实例类ConcretVerticesGraph和ConcreateEgdesGraph:。

熟悉泛型的用法与规则

对给定的文本文件,调用Graph作为存储语料库的数据结构

3.1.1 Get the code and prepare Git repository

通过https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1来fork代码到自己的github账号中,然后在自己的账号中clone代码,在浏览器中下载代码。打开Git Bash,通过网络查找命令行git init使用方式来将自己本地的一个文件夹作为本地库,通过git remote add origin
https://github.com/ComputerScienceHIT/Lab1-1180300412.git命令来将本地库与远程库进行关联。

3.1.2 Problem 1: Test
Graph

使用ConcreteEdgesGraph作为Graph的具体实现,修改graph中的empty方法为:public static Graph empty() {

return new ConcreteEdgesGraph();

}

运行GraphStaticTest得到:

对于GraphInstanceTest.java,由MIT的实验指导可知,必须要使用emptyInstance()方法来获取新的空图。Testing strategy如下:

// addTest()

//    增加点,然后再加入重复的点会失败//    加入完成后,使用contains来判断点集vertices中是否含有之前加入的点//  setTest()//    加入的边原来不存在的话,存储起点和终点,返回0//    假如加入的边已经存在,那么返回该边的在图中的权值;边上有不存在的点的话,先存点//    假如输入的权值为0,则删除图中的这条边,返回0//  removeTest()//    删除存在的点以及与这个点相连的边,删除不存在的点将会失败//  verticesTest()//   没有点的话返回一个空集//   检查加入的点是否在集合里,删除的点是否不再在集合里//  sources()//   输入图中没有的点,图中有的点,检查结果是否与图中的信息一致//  targets()//   与source类似

3.1.3 Problem 2: Implement
Graph

3.1.3.1 Implement ConcreteEdgesGraph

一、ConcreteEdgeGraph:

  1. ConcreteEdgeGraph.java

// Abstraction function:

//

vertices->the collection of vertex in the graph

//   edges->the

edges in the graph

// Representation invariant://   edge can't be

null,one edge can’t be the same as other edges

// Safety from rep exposure://   all fields are

private

// defensive copy

Set()方法中,先检验加入边的起点和终点是否存在在vertices中,如果不存在就使用add()方法先加点,再操作

if(!vertices.contains(source))

    vertices.add(source);

if(!vertices.contains(target))

 vertices.add(target);

遍历边集中的边,检查是否之前已经存在,假如存在的话,判断weight的值,判断是删除这边,还是重置weight值。但是由于edge是不可变类型,所以必须重新构造一个Edge对象。

remove方法,假如点集中不存在要删除的点,则直接返回false。使用迭代器遍历边集,检查边的起点或者终点是否是要删除的点,如果是,则删除。if(edge.getSource().contentEquals(vertex)||edge.getTarget().equals(vertex))itr.remove();

sources()方法,if(edge .getTarget().equals(target))

                      sources.put(edge.getSource(),edge.getWeight());

vertices():使用Collections.unmodifiableSet 来避免表示泄露

CheckRep()方法,检查边集中是否含有null,是否有重复边。

toString方法,如果是空图的话,直接返回提示信息。最初使用concat方法连接字符串,但是在测试时,却与预想的不一样,于是字符串改用“+”连接。

2.calss Edge:

private final String source, target;

private final int weight;

final和private防止边的成员变量被修改和泄露

//
Abstraction function:

//

source->start of the edge,target->end of the edge

//   weight->the

distance between source and target

// Representation invariant://   source and

target can’t be null or same

//   weight>=0// Safety from rep exposure://   all fields are

private and final

// all members are immutable

CheckRep()方法,检查起点和终点是否为空,起点是否和终点相同,权值是否大于等于0

使用构造器初始化

3.test:

ConcreteEdgeGraphTest类继承了GraphInstanceTest,所以不需要再次写在问题一中已经写过的测试了,只需要测试toString和Edge类

toStringTest:

测试策略如下:

//
Testing strategy for ConcreteEdgesGraph.toString()

//   first test

empty graph

//   add vertices

and edges

//   output a

String of information of edges

//   at first,set

three edges,assertFalse;

//   then set

another edge to satisfy the expected String.assertTrue

assertFalse( graph.toString().equals(“a->b:3\nc->b:5\nb->a:3\na->c:2\n”));

graph.set(“a”, “c”, 2);

assertTrue( graph.toString().equals(“a->b:3\nc->b:5\nb->a:3\na->c:2\n”));

EdgeTest:直接创建一个Edge对象,然后测试输出的字符串与预期的是否相同,另外三个观察器不再赘述。

3.1.3.2 Implement ConcreteVerticesGraph

  1. Vertex:
    

Vertex类定义了两个数据:点的字符串名称和以该点为起点的边的终点和权值的散列表。private final String name;

        private final Map<String,Integer> targets=new HashMap<>();

使用构造器来为Vertex对象的name变量赋值。public Vertex(String name)

使用观察器来返回对象的变量,为了防止表示泄露,使用防御式拷贝

getName():return new String(this.name)

getTargets():return new
HashMap<String,Integer>(targets);

setEdge():加入一个边,也就是在这个vertex对象对应的终点集中加入一个点及边的权值targets.put(target,weight);

removeEdge():从点的终点集中删除掉要删除的边的终点targets.remove(target);

toString():假如该对象没有与其他点相连,即其终点和权值的散列表为空,则返回对应的提示信息;否则的话遍历散列表for(String vertex:targets.keySet())

     s=s+this.name+"->"+vertex+":"+targets.get(vertex)+"\n";

checkRep():判断一个点的终点集中是否含有它自己或者是null,然后编历终点集散列表,假如含有权值小于0的边就报错

  1. ConcreteVerticesGraph
    

private final List vertices = new ArrayList<>();

vertices为图中所有点的集合

checkRep():检查点集中是否有null,然后两个循环检查点集中是否有重复的点。

set(String source, String target, int weight):最开始先判断起点和终点是否在图中,假如不在的话就使用add方法加入到点集中,先通过遍历点集,找到起点所在的点对象,然后判断终点是否在对象的终点集中。权值不为0,则重新调用点对象setedge()方法,设置权值。如果权值为0,则调用点对象的removeEdge方法,从起点的终点集里删除掉该终点target。

Remove():遍历终点集,判断是否存在将要删除的点,假如不在就返回false。然后再次遍历点集,假如起点是要删除的点,if(v.getName().equals(vertex))则把该点从vertices集中删除;

假如是点的终点集中存在要删除的点,else if(v.getTargets().containsKey(vertex))就调用点对象的removeEdge方法,从终点集中把要删除的点去掉。

Vertices()方法:Set set=new HashSet<>();

    for(Vertex v:vertices) set.add(v.getName());将每个点的名字字符串加入到创建的set中

targets()方法:遍历点集,假如点和传来的参数点相同,则返回该点的终点和权值的散列表。

Sources():创建一个散列表,遍历点集,假如点的终点集中含有传来的参数target,则将该点和对应的权值put入散列表中。

for(Vertex v:vertices)

      if(v.getTargets().containsKey(target))map.put(v.getName(),v.getTargets().get(target));

toString():首先判断点集是否为空,判断是否所有的点的终点集都为空,假如以上条件满足一个就返回提示空图字符串。然后遍历点集,再将点的终点集进行遍历:

for(Vertex v:vertices) {

               Iterator<Map.Entry<String,

Integer>> itr = v.getTargets().entrySet().iterator();

         while(itr.hasNext()) {Map.Entry<String, Integer> entry = itr.next();s=s+v.getName()+"->"+entry.getKey()+":"+entry.getValue()+"\n";}}
  1. ConcreteVerticesGraphTest():
    

该部分设计原则与ConcreteEdgesGraphTest类似,这里只说明一些不同点。在toStringTest()中预期的字符串要注意书写顺序否则会报错,要按照加入集合的顺序写,先写第一个点的各个终点,如a->b:3\na->cb->a:2

getTargetsTest():在测试时分别验证终点集中是否有已经设置过的边的终点,以及得到的value值

assertTrue(a.getTargets().containsKey(“b”));

    assertTrue(a.getTargets().containsKey("c"));assertFalse(a.getTargets().containsKey("e"));assertTrue(4==a.getTargets().get("d"));assertTrue(3==a.getTargets().get("b"));

setEdgeTest():先不设置边,然后检测a的终点集的大小为0,之后设置边,检测终点集是否有已经加入的点,以及验证对应的value值

removeEdgeTest():加入点和边,然后验证某个点的终点集的大小以及其中含有的键值,然后使用removeEdge,之后再次验证某个点的终点集的大小以及其中含有的键值。

3.1.4 Problem 3: Implement generic Graph

3.1.4.1 Make the implementations generic

将两个实例类中的所有String类的参数替换为泛型的参数,修改后test仍然能够通过。

3.1.4.2 Implement Graph.empty()

将empty()方法修改为:public static Graph empty() {

 Graph<L>

graph = new ConcreteEdgesGraph();

    return graph;

}

这里以ConcreteEdgesGraph作为Graph默认的实例类。

3.1.5 Problem 4: Poetic walks

3.1.5.1 Test GraphPoet

先创建一个GraphPoet对象poet,调用poet.toString()方法得到由文本构造的图输出的字符串,测试这个字符串与预想的是否相同。

分别输入三个句子,使得三句中分别可以插入两个权值不同的桥单词,一个桥词汇,没有桥词汇。预想的句子分别是插入权值最大的桥单词,插入唯一的一个桥单词,没有桥单词被插入,输出句子和原句相同。

assertEquals(“He
brushes his teeth early.”,poet.poem(“He brushes teeth early.”));//two bridge,his:2,your:1

3.1.5.2 Implement GraphPoet

  1. GraphPoet:
    

private final
List words=new ArrayList();//语料库中的单词存入其中

将文本文件一次性打开,然后将文本中的字符全部存入字符串中

Long fileLengthLong =
corpus.length();

    byte[] fileContent = new byte[fileLengthLong.intValue()];try {

FileInputStream inputStream = new FileInputStream(corpus);

inputStream.read(fileContent);

inputStream.close();

    } catch (Exception e) {System.out.println("The file can't be opened

correctly!");

    }String s = new String(fileContent);

使用toLowerCase()函数来将字符串中所有字母都转换成小写字母

然后使用StringTokenizer st = new StringTokenizer(s, " \n");来把所得到的的字符根据空格和换行符进行分割。将分割后的单词们加入到words中。

将所有的单词加入到之前已经实现功能的图结构中graph.add(words.get(i));

使用一个散列表来图中的一个结点的所连边的终点和权值,

Map<String,Integer> map=graph.targets(words.get(i));

判断与这个单词顺序相邻的下一个词所组成的边是否已经存入到了边集中,假如不存在,则将其假如到这个词的终点其权值散列表中,权值为1;

假如这个边已经存在,那么就将其权值加一

if(!map.containsKey(words.get(i+1)))

graph.set(words.get(i), words.get(i+1), 1);

else

graph.set(words.get(i),words.get(i+1), map.get(words.get(i+1))+1);
  1. poem():
    

与上个文本分割相似,将传入的字符串分割成单词

然后创建一个字符串的List:

List
ret=new ArrayList();//将要返回的字符串

遍历语料库中单词的List:在循环中将输入List的起点和终点转换成小写存到两个字符串中,以便和语料库中的某个点的起点和终点相比较。

遍历语料库,假如语料库中的某点的sources中包含有参数字符串中的一个点vertex且targets中含有点vertex的相邻的下一个点,说明这就是bridge,创建一个散列表,将桥与权值存入,再创建一个set来辅助,以防有多个桥时,能够选择权值最大的桥。将这一过程循环,也就是分别处理参数字符串中的第(0,1)(1,2),(2,3),(3,4)……(Words.size()-2,Words.size()-1)个。

使用之前创建的ret,在处理过程中每次将一个source插入以及可能的权值(使用if判断权值是否大于0,来确定是否需要插入权值),终点target暂时不插入;等到下一次循环时,target将变成source,所以不用在上一次循环中插入。由于之前转换小写是使用的是复制后的备份,所以此时插入的还是原始的未转化为小写的单词以及符号。

最后将List分情况将单词重组成字符串。

3.1.5.3 Graph poetry slam

在网络上找一篇英语短诗,然后输入几个词,得到结果,单词数量增加

3.1.6 Before you’re done

3.2 Re-implement
the Social Network in Lab1

使用P1中实现的接口ConcreteVerticesGraph类,重新实现lab1中的FriendshipGraph类,最后使用lab1中的测试用例和客户端函数进行测试。

3.2.1 FriendshipGraph类

使用“private final ConcreteVerticesGraph
graph=new

ConcreteVerticesGraph<>();”语句来创建一个新图,然后在创建一个字符串的List来存储图中所有人的名字:

private final List names=new ArrayList<>();

FriendshipGraph类中的 addVertex方法实现时,首先判断该person对象的名字name在图中所有点的名字组成的List中是否已经存在,假如存在,则直接输出错误信息,退出程序,假如不存在,则graph.add(person);

                                   names.add(person.getname());

将person对象加入到图中,将person对象的名字加入所有点的名字组成的List中。

AddEdge():直接调用P1中实现的方法graph.set(p1, P2, 1);由于是无权图,所以只要将权值都设置为1

getDistance():此部分与Lab1中实现的没有较大差别,只是在遍历某个person的朋友时,使用for(Person friend:graph.targets§.keySet()) 语句进行遍历

Queue queue=new LinkedList();

    HashMap<Person,Integer> distance=new HashMap<Person,Integer>();//每个人离a的距离创建队列和散列表,散列表将每个人与他和原点的距离对应起来使用广度优先搜索,从原点开始进行搜索,对所有的点像层序遍历一样,第二层的点是第一层的点的朋友,到原点距离为distance.get(原点)+1;,然后将第二层的点入队,将第二层的点和他们距原点的距离置入到散列表distance中。然后将队头出队,遍历其朋友,这时已经是第三层了,第三层的点到原点距离为第二层的距离加一,重复上述操作,在遍历时检查点是否是已经遍历过的点(在distance散列表中能够查找到对应键)if(!distance.containsKey(friend)),如果是已经检查过的点,则开始下一个点;以及检查点是不是终点,如果是的话,返回该层与原点的距离。当弹出的队头的朋友遍历完之后,再弹出一个队头元素,对其朋友列表同样进行遍历。重复操作,直到队列为空或函数已经返回。如果上述操作全部完成,则说明终点与原点不连通,返回-1.

第二层的点和第一层的原点距离为0+1,第三层的点和第一层的距离(0+1)+1,第四层的点和第一层距离为[(0+1)+1]+1一直递推就可以求出图中任意一个元素和原点的距离。

3.2.2 Person类

设计一个constructor和observer, 在起名字的时候不会知道是否重名,只有在加入到graph.names中时才能知道,所以在person中不设置判断重名的语句。在加入图中时再进行判断是否重名。

3.2.3 客户端main()

实验要求不变动客户端代码,故直接粘贴lab1中的客户端代码。

3.2.4 测试用例

使用lab1中的测试用例,略微改动以适配FriendshipGraph

3.2.5 提交至Git仓库

3.3 Playing
Chess

3.3.1 ADT设计/实现方案

一、Position类:

private final int x;
x坐标,不可变

  private final int y;  y坐标,不可变

//Abstraction
function:

  //   x,y is the

position of a piece

  //Representation invariant://

x>=0,y>=0

  //Safety from rep exposure://

all fields are private and final

public int getY() 返回position的X坐标

public int getX() 返回position的Y坐标

public boolean equals(Position p) 假如两个position的x,y坐标相等,则返回true

private void checkRep() x或y小于0,则抛出错误

二、Piece类:

private final String name; 棋子类型(白黑/王后象车马兵) 不可变

    private Position position;    棋子位置 可变

private final Player belong; 棋子的所属的玩家 不可变

//
Abstraction function:

// name->the type of the piece

// belong->the player that the piece belongs
to

// position->the position of the piece on
the board

// Representation
invariant:

// piece can’t be null

//
Safety from rep exposure:

// all fields are private

// defensive copy

public
Position getPosition() 得到Piece棋子的位置

public
void setPosition(int x,int y) 将该棋子放置到给定的位置

public
Player getPlayer() 返回该棋子的所属玩家

public
String getName() 返回该棋子的名称(“黑白/王后象马车兵”)

三、Board类:

由于国际象棋棋盘上的格子也可以抽象化为点,如棋子“K”在棋盘上第一行第五列,也可以将它表示为坐标(4,0),其棋盘可以初始化为边长为8的二维数组;围棋本来就是下在交叉点上,故其为边长为19的二维数组。

private final int boardsize;
棋盘的边长 不可变

private Piece[][] BoardPieces; 棋盘抽象为二维数组,数组上的棋子的位置是Piece对象 可变

// Abstraction function:

    //   boardsize->the

length of the board side

    //

BoardPieces->the pieces in that position

    // Representation invariant://   boardsize>0// Safety from rep exposure://   all

fields are private

//Constructor

    public Board(int size) {this.boardsize=size;BoardPieces=new

Piece[size][size];

     for(int

i=size-1;i>=0;i–)

        for(int

j=size-1;j>=0;j–)

            BoardPieces[i][j]=null;checkRep();}

public
void setPiece(Piece p,int x,int y) 在棋盘(x,y)处放置棋子p

public
Piece getPiece(int x,int y) 返回棋盘(x,y)处的棋子对象

public
int getSize() 返回棋盘的边长大小

public
void removePiece(int x,int y) 移除棋盘上位置(x,y)处的棋子

四、Player类:

private final String name;
玩家的名字 不可变

private final String color;
玩家所执棋子的颜色 不可变

private final List pieces=new ArrayList<>(); 玩家所有的棋子的列表 可变

private final List history=new LinkedList<>(); 玩家的走棋历史 可变

// Abstraction function:

    //

name->the name of the player

    //

color->the color of the pieces which belong to the player

    //

pieces->the set of the pieces belongs to the player

    //   history->the

steps history of the player

    // Representation invariant://  // Safety from rep exposure://

all fields are private and final

public
void addStep(String step) 将一步走棋的字符串加入到走棋历史的列表中

public
boolean addPiece(Piece p) 将一枚棋子加入到玩家所拥有的棋子列表中

public
boolean removePiece(Piece d) 将一枚棋子d从玩家所拥有的棋子列表中移除

public
int getnum() 返回玩家的棋子的总数

public
String getColor() 返回玩家所执棋子的总数

public
String getName() 返回玩家的名字

public
List getHistory() 返回玩家的走棋历史列表

五、Action类:

private Board board; 棋盘对象 可变

//Abstraction function:

      //

board -> the board of the game

      //Representation invariant://  //Safety from rep exposure:

//
all fields are private

Constructor:

public
Action(String gameName) {

     if(gameName.equals("chess"))board=new Board(8);else if(gameName.equals("go"))board=new Board(19);if(!gameName.equals("chess")&&!gameName.equals("go"))System.out.println("The game only can

play chess or go.");

public
void putPiece(Player player,Piece piece,int x,int y) 在棋盘上(x,y)位置处放置玩家player的棋子piece,将该棋子加入到玩家palyer的棋子列表中

public
void movePiece(Player player,int x0,int y0,int x,int y) 把玩家player的(x0,y0)位置处的棋子移动到(x,y)处,棋盘(x0,y0)位置处置为null,(x,y)置为board.getPiece(x0, y0)

public
void removePiece(Player player,int x,int y)
把玩家player的位于(x,y)处的棋子移出棋盘,将这个棋子从玩家的拥有的棋子列表中移除,棋盘中(x,y)位置置为null

public
void eatPiece(Player player,int x0,int y0,int x,int y) 使用玩家的(x0,y0)处的棋子吃掉(x,y)处的对方的棋子,也就是把(x0,y0)处置为空,从(x,y)处棋子所属玩家的棋子列表中移除掉该棋子,把(x0,y0)处的棋子移动到(x,y)处

public
Board getBoard() 返回游戏的这个棋盘对象

六、Game类:

private final String gameName; 游戏名称 不可变

private final Action gameAction ;     玩家的操作   不可变private final Player player1;          玩家对象  不可变private final Player player2;          玩家对象  不可变

// Abstraction function:

//

gameName->the name of the player

//

gameAction->the Actions of the player

//

player1->player1 object

//

player2->player2 object

// Representation invariant://

game!=null,player1,player2!=null

// Safety from rep exposure:

// all
fields are private

Constructor:

public
Game(String gameName,String playerName1,String playerName2) {

    this.gameName = gameName;gameAction=new Action(gameName);player1=new

Player(playerName1,“B”);

    player2=new

Player(playerName2,“W”);

}

public void putPiece(Player player, Piece
piece, int x,int y)

public void movePiece(Player player,int
x0,int y0,int x,int y)

public void removePiece(Player player,int
x,int y)

public void eatPiece(Player player,int
x0,int y0,int x,int y)

public Board getBoard()

以上五个函数直接调用Action类中的函数;

public void initChess() 初始化国际象棋棋盘,在棋盘上放置王后车象马兵等棋子,并将棋子加入到对应的玩家的棋子列表中。使用类型如

     Piece K=new Piece("K",player1,4,0);player1.addPiece(K);

gameAction.getBoard().setPiece(K, 4, 0);

的语句16次就可以将16枚棋子初始化到棋盘和玩家的棋子列表中。

public void printBoard()       打印棋盘,二维数组中的空元素输出三个空格,非空元素输出棋子的名称

public
Player getplayer1() 返回玩家1对象

public Player getplayer2() 返回玩家2对象

3.3.2 主程序MyChessAndGoGame设计/实现方案

使用String gamename=in.nextLine();语句来读取玩家输入的游戏名称,输出提示,玩家输入玩家的名字,然后构造一个Game类对象,Game game=new
Game(gamename,player1,player2); 假如游戏是chess,则调用initChess()来初始化国际象棋棋盘。

int i=0;在之后的循环走棋中,每次循环i++,使用i%2的结果来判断应该是哪位玩家走棋;

if(i%2!=0)

    System.out.print("玩家"+game.getplayer1().getName()+"操作:");

else

System.out.print(“玩家”+game.getplayer2().getName()+“操作:”);

使用 System.out.println("/\n请输入你要进行的操作:\n1.放一颗棋子到棋盘上\n"

        +

“2.将一个棋子从一个位置移动到另外一个位置:\n”

        +

“3.提子\n4.吃子\n5.查询某个位置的占用情况:\n6.计算两个玩家在棋盘上的棋子总数\n7.跳过\n”

    +

“8.结束\n”);来输出菜单

Case 1: if(gamename.equals(“chess”))
{

       System.out.println("该操作只适用于围棋!请重新选择操作!\n");i--;break;}

Case 1:是在棋盘上落一子,但是国际象棋的棋子早已初始化完成,之后棋子只能越来越少,不可能会增加,所以该操作只适用于围棋,在下国际象棋时,如果有玩家选择了操作1,那么就输出错误信息,由于本次操作并没有成功执行,所以将i–,使得下一次循环还是该玩家选择操作。

假如选择的是围棋,则调用Piece piece=new
Piece(“B”,game.getplayer1(),x,y);

                     game.putPiece(game.getplayer1(), piece, x, y);

来完成操作,其中的“B”在另一个玩家操作时是“W”,表示棋子颜色的黑白。

然后调用game.printBoard();来输出操作后的棋盘

B为黑棋,W为白棋,由于坐标从0开始,故实际的行数和列数是比坐标的横纵坐标大1

Case 2:操作2为移动棋子,此操作为国际象棋独有,与Case 1类似,选择玩围棋时若选择操作2,则输出错误信息,并让该玩家重新选择操作

如果选择的是的是国际象棋,则读取起始点的坐标和目标点的坐标,调用game.movePiece(game.getplayer1(),
x0, y0, x, y);

或者game.movePiece(game.getplayer2(),
x0, y0, x, y);

Case 3:提子操作为围棋独有,所以与之前设计的一样,在选择玩国际象棋时执行操作3,会输出错误信息,并提示重新输入

如果的确是围棋,那么就读取所要提的棋子坐标,判断所提之子是否为对方棋子,调用game.removePiece(game.getplayer1(),
x, y);

在提子操作后:

Case 4:操作4为吃子,只适用于国际象棋,在选择玩围棋时执行操作4,会输出错误信息,并提示重新输入

若确为国际象棋,则读取起始点和目标点坐标,判断起始点棋子是否为己方棋子,目标点棋子是否是对方棋子,调用game.eatPiece(game.getplayer1(),
x0,y0, x, y);

Case 5:该操作是查询某个位置的占用情况

调用game.getBoard().getPiece(x, y).getPlayer().getName()

和game.getBoard().getPiece(x, y).getName() 即可知道棋子所属玩家名和棋子类型

该操作并为改变棋子的状态,在查询完之后,该玩家继续选择操作

Case 6:操作6是计算双方棋子总数,调用game.getplayer1().getName()和game.getplayer1().getnum()得到玩家名和其所拥有的棋子数

Case 7:该操作是跳过本轮走棋,直接输出提示信息,在走棋历史中加入信息,然后continue

Case 8:结束循环,break

在循环结束后,输出信息来询问玩家是否要查看走棋历史

flag=in.nextInt();

   if(flag==1) {System.out.println("玩家"+game.getplayer1().getName()+"的走棋历史如下:");for(String s:game.getplayer1().getHistory())

{

       System.out.println(s);}

调用game.getPlayer1.getHistory(),来得到玩家的走棋历史,再遍历历史列表即可得到结果

3.3.3 ADT和主程序的测试方案

介绍针对各ADT的各方法的测试方案和testing strategy。

介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。

PisitionTest(),PlayerTest(),PieceTest(),BoardTest()主要是getter和一些简单函数的测试,在此就不再赘述。



ActionTest:

//test
strategy

//create
Player,Action,Piece objects,use all functions to get results to test.

//use the chess as the example to test

Action action=new
Action(“chess”);

Player player=new

Player(“Tom”,“black”);

Piece p1=new

Piece(“K”,player,4,6);

Piece p2=new
Piece(“Q”,player,2,7);

putPiecetest():在一个棋盘上为null的的位置,首先assertTrue(action.getBoard().getPiece(4,
6)==null);然后把这个位置设置为p1,之后assertTrue(action.getBoard().getPiece(4,
6)==p1);

movePieceTest:首先断言移动的目标点为null,然后把最开始定义的p1放置到起点,调用movePiece(),之后测试设置的目标点是否为p1,起点是否变为null,assertTrue(action.getBoard().getPiece(6, 6)==p1);

assertTrue(action.getBoard().getPiece(4,
6)==null);

removePiece():构造一个对手的棋子,使用assertTrue(action.getBoard().getPiece(4,
6)==p1);来测试创建正确,在removePiece()之后,assertTrue(action.getBoard().getPiece(4,
6)==null);判断

提子的位置是否为null.

eatPieceTest():构造敌方和我方的棋子,然后将其放置在棋盘上,调用eatPiece(),然后测试终点是否是我方的棋子,还有我方棋子最开始的地方是否为空了

GameTest:

在测试initChess时,测试棋盘上已经初始化之后的特定位置是否是预想的棋子

软件构造Lab2总结相关推荐

  1. 软件构造lab2 - 实验报告

    软件构造lab2 - 实验报告 1.实验目标概述 2.环境配置 3.实验过程 3.1Poetic Walks 3.1.1Get the code and prepare Git repository ...

  2. 软件构造LAB2心得

    目录   1 实验目标概述 2 实验环境配置 3 实验过程 3.1 Poetic Walks 3.1.1 Get the code and prepare Git repository 3.1.2 P ...

  3. 软件构造Lab2问题解决思路及感想

    1 实验目标概述 1 2 实验环境配置 1 3 实验过程 1 3.1 Poetic Walks 1 3.1.1 Get the code and prepare Git repository 1 3. ...

  4. 哈工大2020软件构造Lab2实验报告

    本项目于3.17日实验课验收,请放心参考 参考时文中有给出一些建议,请查看 基本更新完成 2020春计算机学院<软件构造>课程Lab2实验报告 Software Construction ...

  5. (软件构造)2022哈工大软件构造 lab2内容以及心得

    2022年春季学期 计算学部<软件构造>课程 Lab 2实验报告 姓名 艾浩林 学号 120L021917 班号 2003006 电子邮件 2017869860@qq.com 手机号码 1 ...

  6. HIT 软件构造 lab2实验报告

    2020年春季学期 计算机学院<软件构造>课程 Lab 2实验报告 学号 1180300223 班号 1803002 目录 1 实验目标概述 1 2 实验环境配置 1 3 实验过程 1 3 ...

  7. 哈工大软件构造lab2总结

    目录 1 实验目标概述··· 1 2 实验环境配置··· 1 3 实验过程··· 1 3.1 Poetic Walks· 1 3.1.1 Get the code and prepare Git re ...

  8. 软件构造 Lab2 实验报告

    2021年春季学期 计算学部<软件构造>课程 Lab 2实验报告 姓名 王雨宁 学号 1190201118 班号 1903006 电子邮件 1756840811@qq.com 手机号码 1 ...

  9. 哈工大2020软件构造Lab2 Problem3 Playing Chess 架构设计思路

    哈工大2020春软件构造实验2 Problem 3 Playing Chess 架构设计思路 问题简述 整体结构 ADT功能设计 功能实现路径 问题简述: 设计一款棋类游戏,同时支持国际象棋(Ches ...

最新文章

  1. 程序员下班回家,路上被拦......
  2. html百度地图app,uniapp H5 百度地图(示例代码)
  3. javascript :得到上星期的这一天日期
  4. Java修炼之道--I/O
  5. 新能源维修和计算机应用哪个好,在买新能源车之前 这些事你应该先知道
  6. 编译GDAL使用最新的HDF库配置文件
  7. Java中的对象都是在堆上分配的吗?
  8. python+selenium自动创建随笔
  9. WPF使用Prism框架
  10. 双层PDFmaker
  11. linux c 编程一站式学习.pdf,Linux C编程一站式学习
  12. 无人机动力组装与测试-电机、螺旋桨、电调、电池
  13. ADAUDSP1452 声场 Balance与Fader功能的实现
  14. Ellisys Bluetooth Sniffer 文档 (EEN-BT09) - 访问链接密钥的方法
  15. iOS 11.0新功能
  16. 周末参加“北京干部管理职业技术学院”关于高职课程改革的专家讨论会
  17. OracleBBED工具说明
  18. AI人工智能入门-概念介绍和学习路线
  19. [DR吐槽]——三大卡牌链游到底都是什么货色?
  20. (4.6.30)组件化:Android项目构架演变之路

热门文章

  1. JIL Widget模拟器上网技巧
  2. Virtual Shard
  3. 三星530换固态硬盘_2015款21.5寸苹果I MAC换SSD固态硬盘过程分享
  4. access汇总含义_如何用access进行分类汇总?
  5. excel按季度分类汇总_excel进行分类汇总的五种方法
  6. 一文了解Amazon推荐系统20年变迁
  7. 科技前沿:几款意念控制器
  8. 网站提升排名优化的优点!
  9. 深圳Java培训学习:SpringBoot的yml配置及多环境切换【千锋】
  10. 用Python画小猪佩奇,看完别说你不会