软构第二次实验

软构第二次实验

1 实验目标概述
2 实验环境配置
3 实验过程
3.1 Poetic Walks
3.1.1 Get the code and prepare Git repository
3.1.2 Problem 1: Test Graph
3.1.3 Problem 2: Implement Graph
3.1.3.1 Implement ConcreteEdgesGraph
3.1.3.2 Implement ConcreteVerticesGraph
3.1.4 Problem 3: Implement generic Graph
3.1.4.1 Make the implementations generic
3.1.4.2 Implement Graph.empty()
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
3.1.5.2 Implement GraphPoet
3.1.5.3 Graph poetry slam
3.1.6 Before you’re done
3.2 Re-implement the Social Network in Lab1
3.2.1 FriendshipGraph类
3.2.2 Person类
3.2.3 客户端main()
3.2.4 测试用例
3.2.5 提交至Git仓库
3.3 Playing Chess
3.3.1 ADT设计/实现方案
3.3.2 程序MyChessAndGoGame设计/实现方案
3.3.3 ADT和主程序的测试方案

1 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现ADT。具体来说:
针对给定的应用问题,从问题描述中识别所需的ADT;
设计ADT规约(pre-condition、post-condition)并评估规约的质量;
根据ADT的规约设计测试用例;
ADT的泛型化;
根据规约设计ADT的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
使用OOP实现ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);
测试ADT的实现并评估测试的覆盖度;
使用ADT及其实现,为应用问题开发程序;
在测试代码中,能够写出testing strategy并据此设计测试用例。

2 实验环境配置

3 实验过程

3.1 Poetic Walks
本实验主要目的在于训练ADT的构造和编写,对rep,RI,AF等基本概念进行规范化训练。实验先从一般的String类型入手,逐渐升级为泛型编程,最后再对编写好的ADT进行应用。由易到难地训练了ADT的相关技能。最后的应用也较为有趣。实验总体细节较多,但难度一般,有利于ADT相关概念的理解和应用。

3.1.1 Get the code and prepare Git repository
用所给链接从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。

3.1.2 Problem 1: Test Graph
根据实验要求,我们需要在这一部分先为功能明确的接口编写测试用例。
测试的策略是按照每个方法的功能进行测试。首先测试功能能否正常实现,再测试异常情况能否正确处理。还有调用一个方法会不会导致其他方法产生问题。设计测试策略如下:
1.测试增加点的功能
2.测试增加边的功能:
(1)正常用例
(2)一个初始权为0的用例
(3)起止点都是同一点的用例
(4)源点不存在的用例
(5)目标点不存在的用例
3.测试修改边权值的功能
4.测试获取source的功能
5.测试获取target的功能
6.测试删除边的功能
7.测试删除点(同时删除相关边)的功能

3.1.3 Problem 2: Implement Graph

3.1.3.1 Implement ConcreteEdgesGraph
对ConcreteEdgesGraph.java类,我们首先要规划好AF,RI,rep等属性。
由给定的代码:

决定以下属性:
AF:由顶点集和边集到加权有向图的映射
RI:1.顶点集vertices中不存在同名点
2.边集edges中不存在起点和终点都相同的两条边
对Edge类,同样有如下AF,RI
AF:由起点和终点以及边长到边的映射
RI:1.边长不能为负数

ConcreteEdgesGraph类和Edge类都由构造器、类方法、checkrep、toString构成。
具体实现如下:
Edge类:
类属性
private String source;
private String target;
private int weight=-1;

构造器
public Edge (String source,String target,int weight){
this.source=source;
this.target=target;
this.weight=weight;
}

类方法
1.public static boolean weightEqual(Edge x,Edge y)
功能:判断两条边边长是否相等
2.public int getWeight()
功能:获得边的长度
3.public String getSource()
功能:获得边的起点
4.public String getTarget()
功能:获得边的终点

ConcreteEdgesGraph类:
类属性
private final Set vertices = new HashSet<>();
private final List edges = new ArrayList<>();

构造器
public ConcreteEdgesGraph(){

}

类方法
1.@Override public boolean add(String vertex)
功能:向点集中加入新的点。成功则返回true,失败则返回false
若点已存在,返回false

2.@Override public int set(String source, String target, int weight)
功能:创建由source为起点target为终点边长为weight的边,成功则返回1.若边长为负数或起止点为同一点,返回-1.若从输入数据符合规范,但source到target的边已存在,则删除之,并重新创建替代旧有的边,并返回1。若weight为0则视为删除操作,返回1.

3.@Override public boolean remove(String vertex)
功能:将给定的点从点集中删除,并删除与该点相连的所有边。成功则返回true。若给定点不在点集中,返回false。

4.@Override public Set vertices()
功能:返回当前图的点集。

5.@Override public Map<String, Integer> sources(String target)
功能:寻找所有以给定点为终点的边,添加进一个新建的空有向图,并返回该有向图。

6.@Override public Map<String, Integer> targets(String source)
功能:寻找所有以给定点为起点的边,添加进一个新建的空有向图,并返回该有向图。

3.1.3.2 Implement ConcreteVerticesGraph
类似地,对ConcreteVerticesGraph.java类,我们首先要规划好AF,RI,rep等属性。
AF:由顶点集到加权有向图的映射
RI:1.顶点集vertices中不存在同名点
2.边集edges中不存在起点和终点都相同的两条边

ConcreteVerticesGraph类和Vertex类都由构造器、类方法、checkrep、toString构成。
具体实现如下:
Vertex类:
类属性
private String vertex;
private List target = new ArrayList();
private List weight = new ArrayList();

构造器
public Vertex(String vertex)
{
this.vertex = vertex;
}

类方法
1.public boolean addEdge(String target,int weight)
功能:将target存入当前点vertex的List target中,并将对应的边长weight存入vertex的List weight中,成功则返回true。若边长为负数或target不在点集中或target与vertex为同一点,返回false。

2.public boolean removeEdge(String target)
功能:在vertex的target List中寻找给定的点target的index,找到后vertex.getTarget().remove(index),将target删除,同时将对应位置的边长删除vertex.getGetweight().remove(index),返回true。若target不在vertex的target List中,返回false。

3.public boolean setWeight(String target, int weight)
功能:将从点vertex到点target的边长重置为weight。若target并非vertex的目的点之一则返回false。

4.public String getVertex()
功能:获取vertex的vertex

5.public List getTarget()
功能:获取vertex的target List

6.public List getWeight()
功能:获取vertex的weight List

ConcreteVerticesGraph类:
类属性
private final List vertices = new ArrayList<>();

构造器
public ConcreteVerticesGraph()
{

}

类方法
1.@Override public boolean add(String vertex)
功能: 向点集中加入新的点。成功则返回true,失败则返回false
若点已存在,返回false

2.@Override public int set(String source, String target, int weight)
功能:创建由source为起点target为终点边长为weight的边,成功则返回1.若边长为负数或起止点为同一点,返回-1.若输入数据符合规范,但从source到target的边已存在,则删除之,并重新创建替代旧有的边,并返回1。若weight为0则视为删除操作,返回1.

3.@Override public boolean remove(String vertex)
功能:将给定的点从点集中删除,并删除与该点相连的所有边。成功则返回true。若给定点不在点集中,返回false。

4.@Override public Set vertices()
功能:返回当前图的点集。

5.@Override public Map<String, Integer> sources(String target)
功能:寻找所有以给定点为终点的边,添加进一个新建的空有向图,并返回该有向图。

6.@Override public Map<String, Integer> targets(String source)
功能:寻找所有以给定点为起点的边,添加进一个新建的空有向图,并返回该有向图。

3.1.4 Problem 3: Implement generic Graph
在这一个问题中,我们需要将之前已经实现的Graph升级为泛型类型。并对代码进行完善和修改,使之成为真正可以使用的泛型ADT。

3.1.4.1 Make the implementations generic
这一步不需要重新实现,只需在原代码基础上修改,将之修改为适用于泛型即可。主要通过Eclipse的Edit-Find/Replace功能实现,如下图
在这里插入图片描述

3.1.4.2 Implement Graph.empty()
这里要求实现之前没有实现完成的Graph.empty()方法。在这个方法中我们只需返回一个空图即可。因此实现如下:
public static Graph empty() {
Graph empty=new ConcreteEdgesGraph();
return empty;
}
至此,Graph编写完毕。
接下来编写GraphStaticTest检验Graph能否正确运行。
在GraphStaticTest中分别测试了String Integer Character三种类型,测试均成功通过
至此,编写全部完成。

3.1.5 Problem 4: Poetic walks
在这部分问题中,我们需要利用之前完成的ADT来设计一个程序:用给出的输入初始化为语料库,然后,使用由该语料库定义的词亲和度图来诗意转换输入,最后输出一首小诗。

3.1.5.1 Test GraphPoet
照例先编写测试用例,根据实验要求,我们的测试策略设计如下:
1.toString函数
2.正常输入
3.测试语料库中不存在的词语能否输出
4.测试能否自动补充桥接词

3.1.5.2 Implement GraphPoet
public GraphPoet(File corpus)
功能:读取给定文件中的数据并创建对应加权有向图。
特别注意如下:
1.输入字符串不区分大小写,输入多个相同字符串取第一个输入。如aA aa AA Aa视为同一个字符串,点集中只存储aA。
2.相连的两个字符串视为边。如a b c,则有边a->b边长为1,b->c边长为1.若有多个相同字符串str相连,则视为是str到str的环,权为str个数-1。如aA aa Aa是aA ->aA ,边长为2.

public String poem(String input)
参数:字符串
功能:将输入的字符串拆分后与语料库匹配后完成诗句
1.输入的字符串不区分大小写
2.输入的字符串中可以包含语料库没有的词汇
3.若输入的两个相连词汇front、now,在语料库中有一个词汇bridge,使得存在两条边front->bridge,bridge->now,则把bridge称为桥接词,在完成诗句时将它加入front和now之间

3.1.5.3 Graph poetry slam

3.1.6 Before you’re done

3.2 Re-implement the Social Network in Lab1
FriendshipGraph类的设计主要是用于实现模拟“社交网络”,所以更多地关注成员之间的关系。因此,决定基于Graph以及ConcreteVerticesGraph来完成。

3.2.1 FriendshipGraph类
属性:
public Graph graph=Graph.empty();

构造器:
public FriendshipGraph() {

}

类方法:
public void addVertex(Person vertex)
参数:Person
返回值:void
设计思路:
函数功能为像人际关系图中加入新的人,即向图中加入新的点。直接调用ConcreteVerticesGraph类中的add()方法即可。

public void addEdge(Person person_1,Person person_2)
参数:Person,Person
返回值:void
设计思路:
函数功能为向人机关系图中建立person_1和person_2新的人际关系,即向图中添加新的边。直接调用ConcreteVerticesGraph类中的set()方法即可。
注意:原本的ConcreteVerticesGraph实现的是有向图,而人与人之间的关系是相互的,人际图应该为无向图。所以适当修改ConcreteVerticesGraph类。具体实现为添加从person_1到person_2的边的同时添加person_2到person_1的边。

public int getDistance(Person a, Person b)
参数:Person,Person
返回值:int
设计思路:
函数功能为给出任意两个人的名称,能返回出他们之间的“距离”。Lab1中我们使用图的广度优先遍历算法。但我们可以利用map类型来为每一个节点设一个BFS序号,这样就无需借助栈的数据结构而简单地实现BFS。

3.2.2 Person类
Person类只需要name的属性,并没有其他属性。
具体如下:
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
}
可以发现Person类与String类型没有差别。

3.2.3 客户端main()
Main函数沿用lab1即可,具体如下。

public static void main(String arg[]) {
		
		FriendshipGraph graph = new FriendshipGraph();
		Person rachel = new Person("Rachel");
		Person ross = new Person("Ross");
		Person ben = new Person("Ben");
		Person kramer = new Person("Kramer");
		graph.addVertex(rachel);
		graph.addVertex(ross);
		graph.addVertex(ben);
		graph.addVertex(kramer);
		graph.addEdge(rachel, ross);
		graph.addEdge(ross, rachel);
		graph.addEdge(ross, ben);
		graph.addEdge(ben, ross);
		System.out.println(graph.getDistance(rachel, ross)); 
		//should print 1
		System.out.println(graph.getDistance(rachel, ben)); 
		//should print 2
		System.out.println(graph.getDistance(rachel, rachel)); 
		//should print 0
		System.out.println(graph.getDistance(rachel, kramer)); 
		//should print -1
	}

3.2.4 测试用例

3.2.5 提交至Git仓库

3.3 Playing Chess

3.3.1 ADT设计/实现方案
本实验要求实现6个ADT,命名分别为Game、Player、Board、Piece、Position、Action。具体实现如下:
1.Player
类属性:
public String name;//记录棋手姓名
public List historyOfPosition= new ArrayList<>();
public List historyOfPiece= new ArrayList<>();
//记录棋手每一步所下的棋子和位置
int id;//记录棋手先后顺序
private static int number=1;

构造器:
public Player(String playername) {
this.name=playername;
this.id=number;
number++;
}
类方法:
public void printHistory()
参数:
返回值:void
功能:打印棋手下棋记录

2.Position
类属性:
int xAxis;//横坐标
int yAxis;//纵坐标

构造器:
public Position(int xAxis,int yAxis)
{
this.xAxis=xAxis;
this.yAxis=yAxis;
checkRep();
}

类方法:
public boolean checkRep()
{
if (xAxis<0 || yAxis<0)
return false;
return true;
}

3.Piece
类属性:
String typeOfPiece;//棋子类型,如白棋、黑棋,king、queen等
Player player;//属于哪个棋手
Position position;//坐标
构造器:
public Piece(String typeOfPiece,Player player,int x,int y)
{
Position position=new Position(x,y);
this.typeOfPiece=typeOfPiece;
this.player=player;
this.position=position;
}

4.Board
类属性:
public int size;//棋盘尺寸
public Piece[][] board;//棋盘
String typeOfGame;//游戏类型
List piecesOfP1 = new ArrayList<>();//棋子
List piecesOfP2 = new ArrayList<>();//棋子

构造器:
public Board(Player player1,Player player2,String typeOfGame)
{
if (typeOfGame.equals(“chess”))
chessBoard(player1,player2);//调用函数创建象棋棋盘
if (typeOfGame.equals(“go”))
goBoard(player1,player2);//调用函数创建围棋棋盘
}

类方法:
private void chessBoard(Player player1,Player player2)
参数:Player player1,Player player2
返回值:void
功能:
创建一个8*8的Piece数组作为棋盘,同时调用newPieceOfChess函数创建棋子。

private void goBoard(Player player1,Player player2)
参数:Player player1,Player player2
返回值:void
功能:
创建一个19*19的Piece数组作为棋盘,同时调用newPieceOfGo函数创建棋子。

public void newPieceOfChess(Player player1,Player player2)
参数:Player player1,Player player2
返回值:void
功能:
分别为两个玩家创建整副国际象棋棋子,并将他们初始化在相应位置上。

public void newPieceOfGo(Player player1,Player player2)
参数:Player player1,Player player2
返回值:void
功能:
分别为两个玩家创建整副围棋棋子。

5.Action
类方法:
public static Piece actionOfChess(Player player,
Position source,Position target,Board board)
参数:Player player:执行行动的玩家
Position source:要操作的棋子的原坐标
Position target:要将棋子落下的目的坐标
Board board:已经建好的棋盘
返回值:Piece ate:1.若为空,则操作违规
2.操作合法,未出现吃子,返回本回合操作的棋子
3.操作合法,出现吃子,返回本回合被吃的棋子
功能:
将source上的棋子移动到target上。
1.若source上的棋子不属于player,返回null
2.若target上没有棋子,调用move()
3.若target上已有棋子,且属于player,返回null
4.若target上已有棋子,但不属于player,调用attack()

public static void move(Position source,Position target,Board board)
参数:Position source:要操作的棋子的原坐标
Position target:要将棋子落下的目的坐标
Board board:已经建好的棋盘
返回值:void
功能:
将source上的棋子移动到target上。删除source点上的棋子。actionOfChess已确保输入的正确性,执行功能即可。

public static Piece attack(Position source,
Position target,Board board)
参数:详见actionOfChess函数,不再赘述
返回值:Piece 被吃的棋子
功能:
用source上的棋子吃掉target上的棋子。返回target上的棋子。

public static List actionOfGo(Player player,
Piece piece,Position target,Board board)
参数:Player player:执行行动的玩家
Piece piece:要操作的棋子
Position target:要将棋子落下的目的坐标
Board board:已经建好的棋盘
返回值: List :1.为空,则操作正确,但未出现打吃,未提子
2.为参数piece,操作违规
3.不为空,且非piece,操作正确且打吃,提子
功能:
将选中的piece棋子落到target上。
1.若piece不属于player,返回piece
2.若target上有棋子,返回piece
3.若target上没有棋子,调用go()

public static List go(Piece piece,
Position target,Board board)
参数:参数详见actionOfGo,在此不做赘述
返回值:参见actionOfGo( ),不做赘述
功能:
将选中的piece棋子落到target上。并判断四周是否有气眼,即与target相接的四个点是否有为空的。若有,返回true。若没用,对target处的piece调用函数besiege()判断piece是否有气。情况如下:
1.若target处棋子有气,返回null
2.若target处棋子无气,对target四周相连的对方棋子调用besiege()函数判断是否有气。若无气,调用drive()函数进行提子,并返回null。
3.若target处棋子无气,且与之target四周相连的对方棋子都有气。则该行动不合法,撤销并返回piece。

public static List besiege(Position target,Board board)
参数:参数详见actionOfGo,在此不做赘述
返回值:List pieces
功能:
以target为起点,该点上棋子所属玩家player的棋子作为路径,对手的棋子作为墙壁,空点作为终点进行广度优先搜索。所有搜索过的点保存进pieces中,若最终没有搜到空点null,则这一片棋子无气,pieces中存储的所有棋子均为无气的死子,返回pieces。若存在空点,则这一片棋子有气,用removeAll()将pieces中所有元素均删除,返回空的pieces。

public static void drive(List pieces)
参数:参数详见actionOfGo,在此不做赘述
返回值:void
功能:
从给定目标点开始,删去pieces中所有死子。

6.Game
类属性:
String typeOfGame;
Player player1;
Player player2;
Board board;
Player victor;//记录胜利者

构造器:
public Game(String typeOfGame,String nameOfPlayer1,String nameOfPlayer2) {
this.typeOfGame=typeOfGame;
this.player1=new Player(nameOfPlayer1);
this.player2=new Player(nameOfPlayer2);
this.board=new Board(player1,player2,typeOfGame);
}

类方法:
public static Game start()
参数:
返回值:Game game
功能:
通过键盘读取方式,读取数据创建并返回game。

public void ready()
参数:
返回值:void
功能:
分析读入数据为游戏做准备。如果使用者选择象棋,就调用playingChess(),否则调用playingGo()。数据合法性经过start()检测,无需检测。

public void ifEnd()
参数:
返回值:Player victor
功能:
通过读入指令判断是否投降。投降则游戏结束,对手获胜。

public String ifFun(String order)
参数:String order
返回值:String ret
功能:
因函数中多出需要键盘读入yes或no,为防止大量代码重复并便于检查输入合法性而编写的函数。根据输入的order提醒使用者目前输入的数据和格式,并在读取后返回给调用者。如:
if (order == “skip”)
{
System.out.println(“Do you want to skip? (yes/no)\n”);
}

public Position inputPosition()
参数:
返回值:Position position
功能:
通过键盘读入生成坐标点并返回给调用者。

public void makeSure(Position position)
参数:Position position
返回值:void
功能:
打印棋盘上所给点的信息。若不为空打印棋子类型和所属玩家。

public int count(Player player)
参数:Player player
返回值:int
功能:
清点棋盘上属于player的所有棋子,打印个数并返回。

public Player playingChess(List player)
参数:List player
返回值:Player
功能:
这是游戏主体。通过反复调用子函数进行游戏。将两个玩家存入List player,并根据int i进行循环操作。通过Player actor = player.get(i%2)来实现回合交替。
1.调用ifEnd(),判断是否结束游戏,结束则跳出循环返回胜者victor
2.调用ifFun(“makesure”)判断是否需要清点场上棋子数目
3.循环调用ifFun(“check”)判断是否查看棋盘上某点的具体情况,直到输入no不再查看,退出循环进行下一步
4.调用ifFun(“skip”)判断是否跳过回合,跳过则开始下一轮循环
5.若不跳过,调用inputPosition()读取所需坐标,调用actionOfChess(),成功行动后,将本次行动记录
6.每次完成吃子,判断是否为king,若是,则当前玩家获胜,返回当前玩家。

public Player playingGo(List player)
参数:List player
返回值:Player
功能:
这是游戏主体。通过反复调用子函数进行游戏。将两个玩家存入List player,并根据int i进行循环操作。通过Player actor = player.get(i%2)来实现回合交替。
1.调用ifEnd(),判断是否结束游戏,结束则跳出循环返回胜者victor
2.调用ifFun(“makesure”)判断是否需要清点场上棋子数目
3.循环调用ifFun(“check”)判断是否查看棋盘上某点的具体情况,直到输入no不再查看,退出循环进行下一步
4.调用ifFun(“skip”)判断是否跳过回合,跳过则开始下一轮循环
5.若不跳过,调用inputPosition()读取所需坐标,调用actionOfGo(),成功行动后记录本次行动

3.3.2 程序MyChessAndGoGame设计/实现方案

3.3.3 ADT和主程序的测试方案

Abaqus提供了丰富的二次开发功能,包括用户子程序的开发和与其他商业软件的接口处理。对于本构模型的二次开发,可以使用Abaqus的用户子程序开发功能。用户可以使用Fortran语言编写材料本构关系(UMAT/VUMAT)和自定义单元(UEL)等。这些用户子程序可以根据实际需求来定义材料的行为和本构模型。通过编写用户子程序,可以实现对Abaqus的本构模型进行个性化定制和扩展。\[2\] 需要注意的是,Abaqus的用户子程序开发需要一定的编程知识和经验。在进行二次开发之前,建议先学习Abaqus的二次开发文档和教学视频,以便更好地理解和应用这些功能。此外,Abaqus还提供了丰富的技术支持和社区资源,可以帮助用户解决开发过程中遇到的问题。\[1\] #### 引用[.reference_title] - *1* [Abaqus子程序二次开发学习(二)](https://blog.csdn.net/ZYQ100000/article/details/126686146)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Abaqus 二次开发 应用实例](https://blog.csdn.net/Hulunbuir/article/details/107459511)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [abaqus二次开发概述](https://blog.csdn.net/hdpai2018/article/details/106056173)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值