软件构造lab1

目 录
1 实验目标概述 1
2 实验环境配置 1
3 实验过程 1
3.1 Magic Squares 1
3.1.1 isLegalMagicSquare() 1
3.1.2 generateMagicSquare() 1
3.2 Turtle Graphics 1
3.2.1 Problem 1: Clone and import 2
3.2.2 Problem 3: Turtle graphics and drawSquare 2
3.2.3 Problem 5: Drawing polygons 2
3.2.4 Problem 6: Calculating Bearings 2
3.2.5 Problem 7: Convex Hulls 2
3.2.6 Problem 8: Personal art 2
3.2.7 Submitting 2
3.3 Social Network 2
3.3.1 设计/实现FriendshipGraph类 2
3.3.2 设计/实现Person类 2
3.3.3 设计/实现客户端代码main() 2
3.3.4 设计/实现测试用例 3
3.4 Tweet Tweet 3
3.4.1 Problem 1: Extracting data from tweets 3
3.4.2 Problem 2: Filtering lists of tweets 3
3.4.3 Problem 3: Inferring a social network 3
3.4.4 Problem 4: Get smarter 3
4 实验进度记录 3
5 实验过程中遇到的困难与解决途径 3
6 实验过程中收获的经验、教训、感想 4
6.1 实验过程中收获的经验和教训 4
6.2 针对以下方面的感受 4

1实验目标概述
本次实验通过求解四个问题(其中一个可选),训练基本Java编程技能,能够利用Java OO开发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。另一方面,利用Git作为代码配置管理的工具,学会Git的基本使用方法。
基本的Java OO编程
基于Eclipse IDE进行Java编程
基于JUnit的测试
基于Git的代码配置管理

2实验环境配置
简要陈述你配置本次实验所需开发、测试、运行环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
1.JDK配置
下载JDK,并解压到D:\JDK    
Win10 下环境变量Path的配置    
验证是否配置成功

2.eclipse配置
下载并解压

在Eclipse中运行java 程序

3.GIT配置
下载安装,运行

3实验过程
请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。
为了条理清晰,可根据需要在各节增加三级标题。
3.1Magic Squares
在这里简要概述你对该任务的理解。
任务:
n阶幻方的安排n×n数字,通常不同的整数,在广场,n在所有行,所有列,对角线和相同的常数,在main()函数中调用五次isLegalMagicSquare()函数,将5个文本文件名分别作为参数输入进去,看其是否得到正确的输出(true, false)。需要能够处理输入文件的各种特殊情况,例如:文件中的数据不符合Magic Square的定义(行列数不相等、并非矩阵等)、矩阵中的某些数字并非正整数、数字之间并非使用\t分割等。若遇到这些情况,终止程序执行(isLegalMagicSquare函数返回false),并在控制台输出错误提示信息。
将generateMagicSquare产生的magic square写入文件\src\P1\txt\6.txt中;当输入的n不合法时(n为偶数、n为负数等),不要该函数抛出异常并非法退出,而是提示错误并“优雅的”退出——函数输出false结束。利用前面已经写好的isLegalMagicSquare()函数,在main()函数判断该函数新生成的文本文件6.txt是否符合magic square的定义。

3.1.1isLegalMagicSquare()
按步骤给出你的设计和实现思路/过程/结果。
给出代码,设计思想均有注释
/先读取文件最大行数和列数,判断是否相等,若相等生成nn矩阵,初始化为0,加入数据,[2n+2]数组存储行之和列之和以及对角线之和,添加时判断是否为正整数

  • 添加数据后矩阵存在0也不符合要求

*/
public static boolean isLegalMagicSquare(String fileName) {

	int linenumber = 0, columnnumber = 0;
	try (FileReader reader = new FileReader("src/P1/txt/" + fileName);
			BufferedReader br = new BufferedReader(reader)) {
		String line;
		int i, j, k;
		j = 0;
		i = 0;
		k = 0;
		while ((line = br.readLine()) != null) {
			j++;
			String[] word = line.split("\t");
			i = word.length;
			if (k <= i)
				k = i;
		}
		linenumber = j;
		columnnumber = k;
	} catch (IOException e) {
		e.printStackTrace();
	}
	System.out.println(fileName + "行数为" + linenumber + "," + "列数为" + columnnumber); // 得到行和列数

	if (linenumber != columnnumber) {
		System.out.println("该矩阵不是幻方:行列不等");// 判断行和列是否相等
		return false;
	}

	int matrix[][] = new int[linenumber][columnnumber];
	int[] and = new int[linenumber + columnnumber + 2]; // 建立二维数组存放数据和一维数组存放和

	try (FileReader reader = new FileReader("src/P1/txt/" + fileName);
			BufferedReader br = new BufferedReader(reader)) {
		String line;
		int i, j, k;
		j = 0;
		i = 0;
		while ((line = br.readLine()) != null) {
			String[] word = line.split("\t");
			for (i = 0; i < word.length; i++) {// System.out.println(word[i]);
				for (k = word[i].length(); --k >= 0;) {
					if (!Character.isDigit(word[i].charAt(k))) {
						System.out.println("不是幻方:非正整数"); // 判断是否为正整数
						return false;
					}
				}
				matrix[j][i] = Integer.valueOf(word[i]);
			}
			j++;
		}
	} catch (IOException e) {
		e.printStackTrace();
	}

	for (int m = 0; m < linenumber; m++) {
		for (int n = 0; n < columnnumber; n++) {
			if (matrix[m][n] == 0) {
				System.out.println("不是幻方:不是矩阵"); // 判断是否矩阵缺失
				return false;
			}
			// System.out.print(matrix[m][n]+" ");

		}
		// System.out.println();
	}

	for (int m = 0; m < linenumber; m++) {
		int c = 0;
		for (int n = 0; n < columnnumber; n++) { // 添加行之和
			c = c + matrix[m][n];
		}
		and[m] = c;
	}

	for (int m = 0; m < columnnumber; m++) {
		int c = 0;
		for (int n = 0; n < linenumber; n++) { // 添加列之和
			c = c + matrix[n][m];
		}
		and[m + linenumber] = c;
	}

	int d = 0, p = 0;
	for (int m = 0; m < linenumber; m++) {
		d = d + matrix[m][m];
		p = p + matrix[m][columnnumber - m - 1]; // 添加对角线之和
	}
	and[linenumber + columnnumber] = d;
	and[linenumber + columnnumber + 1] = p;

	for (int q = 1; q < linenumber + columnnumber + 2; q++) {
		if (and[0] != and[q]) {
			System.out.println("不是是幻方,和不相等"); // 判断和是否相等
			return false;
		}
	}
	System.out.println("该矩阵是幻方,和为" + and[0]);
	return true;
}

3.1.2generateMagicSquare()
按步骤给出你的设计和实现思路/过程/结果。
设计思路:
/奇数矩阵时依次填入1到n^2,第一个填在第一行正中间,依次向上和向右移动一位,顺序填写,第一行向上会到最后一行,最右向右会到最左,每填n个数,下一个数填在该数下面
直至填完.以3为例子,假设没填的该位置是0,如图
0 1 0 | 0 1 0 | 0 1 0 | 0 1 0 | 0 1 0 | 0 1 6 | 0 1 6 | 8 1 6 | 8 1 6
0 0 0 | 0 0 0 | 3 0 0 | 3 0 0 | 3 5 0 | 3 5 0 | 3 5 7 | 3 5 7 | 3 5 7
0 0 0 | 0 0 2 | 0 0 2 | 4 0 2 | 4 0 2 | 4 0 2 | 4 0 2 | 4 0 2 | 4 9 2
/
public static void generateMagicSquare(int n) throws IOException {
if (n % 2 == 0 || n < 0) {
System.out.println(“输入错误”);
System.exit(-1);
}

	int magic[][] = new int[n][n]; // 创建n*n大小二维数组
	int row = 0, col = n / 2, i, j, square = n * n; // 初始位置在第一行正中间(奇数时)

	for (i = 1; i <= square; i++) {
		magic[row][col] = i;
		if (i % n == 0) // 填完n个数时,n+1在n的下一行
			row++;
		else {
			if (row == 0) // 行为第一行时,上一行为为最后一行
				row = n - 1;
			else
				row--; // 向上移动一行
			if (col == (n - 1)) // 列为最后一列时右边是首列
				col = 0;
			else
				col++; // 向右移动一行
		}
	}
	File file = new File("src/P1/txt/6.txt");
	Writer er = new FileWriter(file);
	er.close();
	Writer out = new FileWriter(file, true);

	for (i = 0; i < n; i++) {
		for (j = 0; j < n; j++) {
			System.out.print(magic[i][j] + "\t"); // 输出二维数组
			String data = magic[i][j] + "\t";
			out.write(data);
		}
		System.out.println();
		out.write("\n");
	}
	out.close();
}

分析异常 ?/ 不能为偶数,分n批,每批写n个,每批结束时不能在最后一行,因为row会++,造成数组越界,而函数第一行开始,注定偶数行为结束行,因此不能为偶数
// 数组创建时元素个数不能为负数

3.2Turtle Graphics
在这里简要概述你对该任务的理解。
任务:熟悉junit,对要求函数进行补全

3.2.1Problem 1: Clone and import
从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
3.2.2Problem 3: Turtle graphics and drawSquare
turtle前进sidelength,右转90度,循环四次.即为正方形
3.2.3Problem 5: Drawing polygons
通过多边形外角和为360度这一性质,已知边数和边长,利用180.00 * (sides - 2) / sides可求得内角.turtle前进sidelength,右转内角度数,循环边数次.即为该正多边形

3.2.4Problem 6: Calculating Bearings
不断获得一个点和下一个点坐标,循环xCoords.size() - 1次,每次n保存和上一条边偏移量,m保存该与y轴的偏移量,调用n=calculateBearingToPoint(m, x1, y1, x2, y2),m=m+n;list不断添加n即可得到list
3.2.5Problem 7: Convex Hulls
1.选取最右下角的点
2.找到第二个点连上前一个点与x轴逆时针旋转夹角最小的一个点,加入集合,依此类推
3.循环时判断是否下一个点和第一个点旋转角度相等,若相等,则结束.
4.返回集合
3.2.6Problem 8: Personal art
turtle.color(PenColor.BLUE);
for (int i = 0; i < 4; i++) {
turtle.turn(30);
turtle.forward(50);
turtle.turn(120);
turtle.forward(50);
turtle.turn(300);
}
可以画出一个蓝色的飞镖形状
3.2.7Submitting
如何通过Git提交当前版本到GitHub上你的Lab1仓库。
使用命令git push -u origin master
3.3Social Network
在这里简要概述你对该任务的理解。
任务:建立一个图,通过输入搭建有向社交网,并且给出正确的输出,对非法输入进行正确的判断。
3.3.1设计/实现FriendshipGraph类
给出你的设计和实现思路/过程/结果。
private List nameList = new ArrayList<>(); // 名字列表,邻接表的展示结构,效率较高。在List类型内装入Person类型,而且每一个Person内有List存储每一个人的序号。
private boolean existName(Person name) // 判断是否graph中存在
public boolean addVertex(Person name) // 向图中添加成员
public boolean addEdge(Person name1, Person name2) //加上关系
public int getDistance(Person name1, Person name2) //获得距离(bfs)
3.3.2设计/实现Person类
给出你的设计和实现思路/过程/结果。
private String name; // person的名字
private List id = new ArrayList<>(); // 和该person有关的其他person序号list
public String getName() // 获得名字
public List getId() // 为获得有关列表
public boolean existId(int id) // 判断是否关系已存在
public void Setid(int a) // 添加关系
public Person(String name) // person名字赋值
3.3.3设计/实现客户端代码main()
给出你的设计和实现思路/过程/结果。
public static void main(String[] args) {

	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.3.4设计/实现测试用例
给出你的设计和实现思路/过程/结果。
package P3;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
public class FriendshipTest {
FriendshipGraph graph = new FriendshipGraph();
Person rachel = new Person(“Rachel”);
Person ross = new Person(“Ross”);
Person ben = new Person(“Ben”);
Person kramer = new Person(“Kramer”);
Person tom = new Person(“Tom”);
Person jack = new Person(“Jack”);

@Test
public void addVertextest() { // 测试往图中加点
	assertEquals(true, graph.addVertex(rachel));
	assertEquals(true, graph.addVertex(ross));
	assertEquals(true, graph.addVertex(ben));
	assertEquals(false, graph.addVertex(rachel)); // 测试重复加点
	assertEquals(false, graph.addVertex(ross));
	assertEquals(false, graph.addVertex(ben));
}

@Test
public void addEdgetest() { // 测试建立关系
	graph.addVertex(rachel);
	graph.addVertex(ross);
	graph.addVertex(ben);
	graph.addVertex(kramer);
	assertEquals(true, graph.addEdge(rachel, ross));
	assertEquals(true, graph.addEdge(ross, rachel));
	assertEquals(true, graph.addEdge(ross, ben));
	assertEquals(true, graph.addEdge(ben, ross));
	assertEquals(false, graph.addEdge(jack, ross)); // 测试有一个或两个人都不在图里加关系
	assertEquals(false, graph.addEdge(ben, tom));
	assertEquals(false, graph.addEdge(jack, tom));
}

@Test
public void getDistancetest() { // 测试获得两者最小距离
	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);
	assertEquals(1, graph.getDistance(rachel, ross), 0.001); // 主函数测试
	assertEquals(2, graph.getDistance(rachel, ben), 0.001);
	assertEquals(0, graph.getDistance(rachel, rachel), 0.001);
	assertEquals(-1, graph.getDistance(rachel, kramer), 0.001);
	assertEquals(-2, graph.getDistance(tom, rachel), 0.001); // 测试有一个或两个人都不在图里的距离
	assertEquals(-2, graph.getDistance(rachel, jack), 0.001);
	assertEquals(-2, graph.getDistance(tom, jack), 0.001);
}

}

3.4Tweet Tweet
请自行组织子目录结构。
3.4.1Problem 1: Extracting data from tweets
Timespan getTimespan(List tweets) 的设计思想:a记录最早时间,b记录最晚时间并都初始化为第一个tweet的timetamp,遍历tweets,每次a如果在某一tweet时间后则其替换a;b同理,即可得到最早和最晚时间.
public static Timespan getTimespan(List tweets) { //获得最早和最晚消息
// throw new RuntimeException(“not implemented”);
Instant a = tweets.get(0).getTimestamp();
Instant b = tweets.get(0).getTimestamp();

	for (int i = 0; i < tweets.size(); i++) {
		if (a.isAfter(tweets.get(i).getTimestamp())) {
			a = tweets.get(i).getTimestamp();
		}

	}
	for (int i = 0; i < tweets.size(); i++) {
		if (b.isBefore(tweets.get(i).getTimestamp())) {
			b = tweets.get(i).getTimestamp();
		}

	}
	Timespan timespan = new Timespan(a, b);
	return timespan;
}

Set getMentionedUsers(List tweets)的设计思想:遍历tweets,每次获得tweet的text,找到text的@的下标,从@下标开始直到找到不为[a-z]||[A-Z]||-||_,截取这一段,判断大小写以及是否存在,选择加入names集合中
public static Set getMentionedUsers(List tweets) { // 获得所有消息中@的人
// throw new RuntimeException(“not implemented”);
Set names = new HashSet<>();
String aString;
String bString = null;

	for (int i = 0; i < tweets.size(); i++) {
		aString = tweets.get(i).getText();

		int m = aString.indexOf("@");

		for (int j = m + 1; j < aString.length(); j++) {
			char k = aString.charAt(j);

			int p = (int) k;

			if ((p == 45) || (48 <= p && p <= 57) || (65 <= p && p <= 90) || (97 <= p && p <= 122) || p == 95) {
			} else {
				bString = aString.substring(m + 1, j);
				// System.out.println(bString);
				break;
			}
		}
		//System.out.println(bString);
		names.add(bString.toLowerCase());
	}
	return names;
}

3.4.2Problem 2: Filtering lists of tweets
List writtenBy(List tweets, String username)设计思想:遍历tweets,如果username不分大小写和tweet的作者名字相等,则alst添加该条tweet,返回alist
public static List writtenBy(List tweets, String username) { //获得一个用户所有发出去的消息
//throw new RuntimeException(“not implemented”);
List aList= new ArrayList();
for (int i = 0; i <tweets.size(); i++) {
if(username.equalsIgnoreCase(tweets.get(i).getAuthor()))
{
aList.add(tweets.get(i));
}

	}
	return aList;
}

List inTimespan(List tweets, Timespan timespan) 的设计思想:遍历tweets,如果一条tweet的timetamp在start和end之间,则添加该tweet到alist.返回aslit
public static List inTimespan(List tweets, Timespan timespan) { //获得所有在规定时间的消息
//throw new RuntimeException(“not implemented”);
List aList= new ArrayList();
for (int i = 0; i <tweets.size(); i++) {
if(timespan.getStart().isBefore(tweets.get(i).getTimestamp())&&tweets.get(i).getTimestamp().isBefore(timespan.getEnd()))
{
aList.add(tweets.get(i));
}

	}
	return aList;

}
List containing(List tweets, List words) 的设计思想:
遍历tweets,遍历words,如果该tweet的text不分大小写包含该word,添加该tweet到alist,返回alist.
public static List containing(List tweets, List words) { //获得所有包含关键字的消息
//throw new RuntimeException(“not implemented”);
List aList= new ArrayList();
for (int i = 0; i <tweets.size(); i++) {
for(int j=0;j<words.size();j++)
{
if(tweets.get(i).getText().toLowerCase().contains(words.get(j).toLowerCase()))
{
aList.add(tweets.get(i));
break;
}
}
}
return aList;
}
3.4.3Problem 3: Inferring a social network
Map<String, Set> guessFollowsGraph(List tweets)的设计思想:遍历tweets,获得每个user的tweet列表,从该列表中获得@对象集合,将其加入map
public static Map<String, Set> guessFollowsGraph(List tweets) {
// throw new RuntimeException(“not implemented”);
Map<String, Set> aMap = new HashMap<>();
List aList = new ArrayList();

	for (int i = 0; i < tweets.size(); i++) {
		aList = Filter.writtenBy(tweets, tweets.get(i).getAuthor());
		Set<String> cSet = new HashSet<String>();
		cSet = Extract.getMentionedUsers(aList);

		aMap.put(tweets.get(i).getAuthor().toLowerCase(), cSet);
	}
	return aMap;
}

List influencers(Map<String, Set> followsGraph) 的设计思想:
建立新map,遍历followsGraph,访问每个user的@的人,在新map的键值对的value上不断++;从而得到一个user和其影响到人数的键值对的map,最后对其降序排序存放key到list中
public static List influencers(Map<String, Set> followsGraph) {
// throw new RuntimeException(“not implemented”);
Map<String, Integer> aMap = new TreeMap<>();
List cList = new ArrayList();
for (String user : followsGraph.keySet()) {
Set aSet = followsGraph.get(user);
for (String bString : aSet) {
if (!aMap.containsKey(bString))
aMap.put(bString, 0);
aMap.put(bString, aMap.get(bString) + 1);

		}
	}
	List<Map.Entry<String, Integer>> wordMap = new ArrayList<Map.Entry<String, Integer>>(aMap.entrySet());
	// System.out.println(wordMap);
	Collections.sort(wordMap, new Comparator<Map.Entry<String, Integer>>() {
		public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
			double result = o2.getValue() - o1.getValue();
			if (result > 0)
				return 1;
			else if (result == 0)
				return 0;
			else
				return -1;
		}
	});
	// System.out.println(wordMap);
	for (Map.Entry<String, Integer> set : wordMap) {
		cList.add(set.getKey());
		// System.out.println(set.getKey() +"   "+set.getValue());
	}

	return cList;
}

3.4.4Problem 4: Get smarter
Map<String, Set> guessSmarterFollowsGraph(List tweets)的设计思想:在原有guessFollowsGraph函数基础上改动,在最内层循环中加入一层对alist中的人再次获得其@到的人,并添加到相应的set中
// smarter 如果A->B,B->C;则A->C
public static Map<String, Set> guessSmarterFollowsGraph(List tweets) {
// throw new RuntimeException(“not implemented”);
Map<String, Set> aMap = new HashMap<>();
List aList = new ArrayList();

	Set<String> cSet = new HashSet<String>();

	for (int i = 0; i < tweets.size(); i++) { // 遍历tweets
		aList = Filter.writtenBy(tweets, tweets.get(i).getAuthor()); // 获取一个author 的所有tweets

		Set<String> fSet = new HashSet<String>();
		fSet.clear();
		cSet.clear();
		cSet = Extract.getMentionedUsers(aList);

		for (String dString : cSet) {

			List<Tweet> gList = Filter.writtenBy(tweets, dString);
			Set<String> nSet = Extract.getMentionedUsers(gList);

			for (String lString : nSet)
				fSet.add(lString);

		}

		fSet.addAll(cSet);

		if (fSet.contains(tweets.get(i).getAuthor().toLowerCase())) {
			fSet.remove(tweets.get(i).getAuthor().toLowerCase());
		}

		aMap.put(tweets.get(i).getAuthor().toLowerCase(), fSet);

	}
	System.out.println(aMap);
	return aMap;

4 }实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 时间段 任务 实际完成情况
2019-02-25 15:45-17:30 编写问题1的isLegalMagicSquare函数并进行测试 按计划完成
2019-03-02 13:00-17:00 编写问题2的turtlesoup类并进行测试 按计划完成
2019-03-09 9:00-11:30
19:00-22:30 编写问题3的friendship类,person类,friendshiptest类并进行测试 按计划完成
2019-03-10 13:30-17:30
20:00-22:30 编写问题4的extract类,filter类,socialnetwork类,smarter函数并进行测试 按计划完成
5实验过程中遇到的困难与解决途径
遇到的难点 解决途径

Git不会使用
查看群文件资料

Java的map排序不会
百度
Java文件读写不会

百度

6实验过程中收获的经验、教训、感想
6.1实验过程中收获的经验和教训
收获:学会了一部分Java编程知识,
6.2针对以下方面的感受
(1)Java编程语言是否对你的口味?

(2)关于Eclipse IDE
导入函数库很方便,纠正错误也很方便,就是在打开外部复制来文件时要重新配置
(3)关于Git和GitHub
进度能够查询清楚
(4)关于CMU和MIT的作业
任务量适中,有些任务叙述不是太明确
(5)关于本实验的工作量、难度、deadline
工作量略微有点大;难度适中;可以按时完成
(6)关于初接触“软件构造”课程
讲义写的较为清晰,如果有中文版的就更好了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值