BLOG-2
阅读原文时间:2023年07月08日阅读:6

前言

 这几次的PTA作业和考试涉及到的知识点有面向对象中对数据的封装,还有继承和多态,还有抽象类和对象容器 也涉及到了一些,同时还有关于正则表达式的一些内容。而关于题量,这应该对于一个初学者来说是一个比较适当的一个量,比较有针对性。至于难度,有难的也有容易的,难的让你找不到一点头绪,其实就是算法太复杂,一时半会让人摸不着头脑,而简单的就一看就知道怎么写,所以对我来说,难度就是两极分化。哎,主要还是自己许多知识只是浅浅地学了一些皮毛,导致做题速度太慢,难度也随速度变得更大。

设计与分析

点线形系列4-四边形题目说明:
用户输入一组选项和数据,进行与四边形有关的计算。
以下四边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
选项包括:
1:输入四个点坐标,判断是否是四边形、平行四边形,判断结果输出true/false,结果之间以一个英文空格符分隔。
2:输入四个点坐标,判断是否是菱形、矩形、正方形,判断结果输出true/false,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
3:输入四个点坐标,判断是凹四边形(false)还是凸四边形(true),输出四边形周长、面积,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
4:输入六个点坐标,前两个点构成一条直线,后四个点构成一个四边形或三角形,输出直线与四边形(也可能是三角形)相交的交点数量。如果交点有两个,再按面积从小到大输出四边形(或三角形)被直线分割成两部分的面积(不换行)。若直线与四边形或三角形的一条边线重合,输出"The line is coincide with one of the lines"。若后四个点不符合四边形或三角形的输入,输出"not a quadrilateral or triangle"。
后四个点构成三角形的情况:假设三角形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z 不与xy都相邻,如z x y s、x z s y、x s z y
5:输入五个点坐标,输出第一个是否在后四个点所构成的四边形(限定为凸四边形,不考虑凹四边形)或三角形(判定方法见选项4)的内部(若是四边形输出in the quadrilateral/outof the quadrilateral,若是三角形输出in the triangle/outof the triangle)。如果点在多边形的某条边上,输出"on the triangle或者on the quadrilateral"。若后四个点不符合四边形或三角形,输出"not a quadrilateral or triangle"。

……

这道题是前几次点线面问题的进阶版,从之前的点线面的判断一直到现在的对不规则的四边形的计算,奈何本人能力有限,只能写出一两个符合要求,所以这道题只得了一小部分的分数。但是对于这道题,我还是要解释一下,首先就是对输入点的判断,在吸取了前几次做点线计算的教训后,本应该可以直接复制之前的对输入点的判断来判断输入的合法性,但是在写过用正则表达式的另一道题后,我觉得用正则表达式可以简化代码,而且可以使判断过程更加清楚明了。

判断代码如下:

public boolean basicjudge() {
boolean flag=true;
for(int i=0;i<point.length;i++) {
if(point[i].length()<3) {
flag=false;
break;
}
}
if(flag) {
for(int i=0;i<point.length;i++) {
if(point[i].contains(",")) {
String []num = point[i].split(",");
if(num.length==2) {
String find="^[\\+\\-]?[\\d]+(\\.[\\d]+)?$";
if(num[0].matches(find)&&num[1].matches(find)) {
continue;
}
else {
flag=false;
break;
}
}
else {
flag=false;
break;
}
}
else {
flag=false;
break;
}
}
}
return flag;
}

public boolean numberjudge() {  
    boolean flag=true;  
    if(point.length!=sum) {  
        flag=false;  
    }  
    return flag;  
}

  在判断合法性之后,接下来就是根据输入的序号来来计算一一对应的要求,虽然我并没有写全所有代码,但是接下来我还是来勉强说一下自己的思路:

1、对于第一要求,我觉得就是要了解平行四边形的性质,比如平行四边形的相对的两边平行且相等。运用这个性质,就要求两点之间的距离,还有两点之间的斜率,还要注意两点的X坐标相等的情况。

  要求1代码如下:

private void calculate1(double[] xy1, double[] xy2, double[] xy3, double[] xy4, double[][] xy) {
if(!judge(xy)) {
System.out.print("points coincide");
}
else {
if(xy1[0]==xy2[0]) {
if(xy3[0]!=xy1[0]&&xy4[0]!=xy1[0]) {
if((xy3[0]==xy4[0]&&Math.abs(xy3[1]-xy4[1])==Math.abs(xy1[1]-xy2[1]))||
(xy3[0]+xy4[0])/2==xy1[0]) {
System.out.print(true+" "+true);
}
else {
System.out.print(true+" "+false);
}
}
else {
System.out.print(false+" "+false);
}
}
else {
double k=(xy1[1]-xy2[1])/(xy1[0]-xy2[0]);
double b=xy1[1]-k*xy1[0];
if(k*xy3[0]+b!=xy3[1]&&k*xy4[0]+b!=xy4[1]) {
if(xy3[0]==xy4[0]) {
if((xy1[0]+xy2[0])/2==xy4[0]&&(xy3[1]+xy4[1])/2==(xy1[1]+xy2[1])/2) {
System.out.print(true+" "+true);
}
else {
System.out.print(true+" "+false);
}
}
else {
double k1=(xy3[1]-xy4[1])/(xy3[0]-xy4[0]);
double L1=Math.sqrt(Math.pow(xy1[1]-xy2[1],2)+Math.pow(xy1[0]-xy2[0],2));
double L2=Math.sqrt(Math.pow(xy3[1]-xy4[1],2)+Math.pow(xy3[0]-xy4[0],2));
if((k==k1&&L1==L2)||(xy1[0]+xy2[0])/2==(xy4[0]+xy3[0])/2&&(xy3[1]+xy4[1])/2==(xy1[1]+xy2[1])/2 ){
System.out.print(true+" "+true);
}
else {
System.out.print(true+" "+false);
}
}
}
else {
System.out.print(false+" "+false);
}
}
}

}

2、第二个要求是基于第一个要求的,这时候就要了解菱形、矩形和 正方形的不同点,当然首先还要判断四点是否是平行四边形,其次应该先判断是否为菱形,再在菱形的基础上判断 是否有两条线是否是直角来进一步判断正方形;另外在非菱形的情况下判断长方形,之后在是长方形的基础上判断正方形。

  要求2代码如下:

private void calculate2(double[] xy1, double[] xy2, double[] xy3, double[] xy4, double[][] xy) {
if(!judge(xy)) {
System.out.print("points coincide");
}
else {
if(xy1[0]==xy2[0]) {
if(xy3[0]!=xy1[0]&&xy4[0]!=xy1[0]) {
if((xy3[0]==xy4[0]&&Math.abs(xy3[1]-xy4[1])==Math.abs(xy1[1]-xy2[1]))||
(xy3[0]+xy4[0])/2==xy1[0]) {
if((xy3[1]==xy1[1]&&xy4[1]==xy2[1])||(xy4[1]==xy1[1]&&xy3[1]==xy2[1])) {
if(Math.abs(xy1[0]-xy3[0])==Math.abs(xy1[1]-xy2[1])) {
System.out.print(true+" "+true+" "+true);
}
else {
System.out.print(false+" "+true+" "+false);
}
}
else if(Math.abs(xy3[1]-xy4[1])==Math.sqrt(Math.pow(xy3[1]-xy1[1],2)+Math.pow(xy3[0]-xy1[0],2))||
Math.abs(xy3[1]-xy4[1])==Math.sqrt(Math.pow(xy3[1]-xy2[1],2)+Math.pow(xy3[0]-xy2[0],2))){
System.out.print(true+" "+false+" "+false);
}
else {
System.out.print(false+" "+false+" "+false);
}
}
else {
System.out.print(false+" "+false+" "+false);
}
}
else {
System.out.print("not a quadrilateral");
}
}
else {
double k=(xy1[1]-xy2[1])/(xy1[0]-xy2[0]);
double b=xy1[1]-k*xy1[0];
if(k*xy3[0]+b!=xy3[1]&&k*xy4[0]+b!=xy4[1]) {
if(xy3[0]==xy4[0]) {
if((xy1[0]+xy2[0])/2==xy4[0]&&(xy3[1]+xy4[1])/2==(xy1[1]+xy2[1])/2) {
if(Math.pow(xy3[1]-xy4[1],2)==Math.pow(xy1[1]-xy2[1],2)+Math.pow(xy1[0]-xy2[0], 2)) {
if(xy1[1]==xy2[1]) {
System.out.print(true+" "+true+" "+true);
}
else {
System.out.print(false+" "+true+" "+false);
}
}
else if(xy1[1]==xy2[1]) {
System.out.print(true+" "+false+" "+false);
}
else {
System.out.print(false+" "+false+" "+false);
}
}
System.out.print(false+" "+false+" "+false);
}
else {
double k1=(xy3[1]-xy4[1])/(xy3[0]-xy4[0]);
double L1=Math.pow(xy1[1]-xy2[1],2)+Math.pow(xy1[0]-xy2[0],2);
double L2=Math.pow(xy3[1]-xy4[1],2)+Math.pow(xy3[0]-xy4[0],2);
if((k==k1&&L1==L2)||(xy1[0]+xy2[0])/2==(xy4[0]+xy3[0])/2&&(xy3[1]+xy4[1])/2==(xy1[1]+xy2[1])/2 ){
double L3=Math.pow(xy3[1]-xy2[1],2)+Math.pow(xy3[0]-xy2[0],2);
double L4=Math.pow(xy4[1]-xy2[1],2)+Math.pow(xy4[0]-xy2[0],2);
if(L2+L3==L4){
if(L2==L3) {
System.out.print(true+" "+true+" "+true);
}
else {
System.out.print(false+" "+true+" "+false);
}
}
else if(L4+L2==L3){
if(L4==L2) {
System.out.print(true+" "+true+" "+true);
}
else {
System.out.print(false+" "+true+" "+false);
}
}
else {
if(L4==L2||L3==L2) {
System.out.print(true+" "+false+" "+false);
}
else {
System.out.print(false+" "+false+" "+false);
}
}
}
else {
System.out.print(false+" "+false+" "+false);
}
}
}
else {
System.out.print("not a quadrilateral");
}
}
}
}

3.第三个要求也是在部分要求1的情况下判断的,判断它是凸四边形还是凹四边形可以通过下面的计算方法来实现。而四边形的周长就是用勾股定理来计算,面积可以用海伦公式来计算。计算完了之后可以通过“DecimalFormat("0.000000").format(d);”来进行四舍五入。

  要求3代码如下:

private void calculate3(double[] xy1, double[] xy2, double[] xy3, double[] xy4, double[][] xy) {
if(!judge(xy)) {
System.out.print("points coincide");
}
else {
boolean a=true;
if(xy1[0]==xy2[0]) {
if(xy3[0]!=xy1[0]&&xy4[0]!=xy1[0]) {
aotujudge(xy1,xy2,xy3,xy4);
}
else {
a=false;
System.out.print("not a quadrilateral");
}
}
else {
double k=(xy1[1]-xy2[1])/(xy1[0]-xy2[0]);
double b=xy1[1]-k*xy1[0];
if(k*xy3[0]+b!=xy3[1]&&k*xy4[0]+b!=xy4[1]) {
aotujudge(xy1,xy2,xy3,xy4);
}
else {
a=false;
System.out.print("not a quadrilateral");
}
}
if(a==true) {
double L1=Math.sqrt(Math.pow(xy1[1]-xy2[1],2)+Math.pow(xy1[0]-xy2[0],2));
double L2=Math.sqrt(Math.pow(xy1[1]-xy3[1],2)+Math.pow(xy1[0]-xy3[0],2));
double L3=Math.sqrt(Math.pow(xy2[1]-xy4[1],2)+Math.pow(xy2[0]-xy4[0],2));
double L4=Math.sqrt(Math.pow(xy3[1]-xy4[1],2)+Math.pow(xy3[0]-xy4[0],2));
double L5=Math.sqrt(Math.pow(xy1[1]-xy4[1],2)+Math.pow(xy1[0]-xy4[0],2));
double C=L1+L2+L3+L4;
double s1=(L1+L3+L5)/2;
double s2=(L2+L4+L5)/2;
double S1=Math.sqrt(s1*(s1-L1)*(s1-L3)*(s1-L5));
double S2=Math.sqrt(s2*(s2-L2)*(s2-L4)*(s2-L5));
simplify(C,S1+S2);
}
}
}

private void simplify(double C1, double d) {  
    String a=String.valueOf(C1);  
    String b=String.valueOf(d);  
    char \[\]m=a.toCharArray();  
    char \[\]n=b.toCharArray();  
    int n1=0;  
    int n2=0;  
    int m1=0;  
    int m2=0;  
    for(int i=0;i<m.length;i++) {  
        if(m\[i\]=='.') {  
            n1=m.length-i-1;  
            m1=i;  
            break;  
        }  
    }  
    for(int i=0;i<n.length;i++) {  
        if(m\[i\]=='.') {  
            n2=m.length-i-1;  
            m2=i;  
            break;  
        }  
    }  
    if(n1>6) {  
        int am=(int)C1;  
        if(m\[m1+7\]>='5') {  
                String num=new DecimalFormat("0.000000").format(C1);  
                if(Double.parseDouble(num)==am) {  
                    System.out.print(num+" ");  
                }  
                else {  
                    System.out.print(num+" ");  
                }  
        }  
        else {  
            if(Double.parseDouble(a)==am) {  
                System.out.printf("%.1f ",C1);  
            }  
            else {  
                System.out.print(C1+" ");  
            }

        }  
    }  
    else {  
        System.out.print(C1+" ");  
    }  
    if(n2>6) {  
        int am=(int)d;  
        if(m\[m2+7\]>='5') {  
                String num=new DecimalFormat("0.000000").format(d);  
                if(Double.parseDouble(num)==am) {  
                    System.out.printf("%.1f ",d);  
                }  
                else {  
                    System.out.print(num);  
                }  
        }  
        else {  
            if(Double.parseDouble(b)==am) {  
                System.out.printf("%.1f ",d);  
            }  
            else {  
                System.out.print(d);  
            }  
        }  
    }  
    else {  
        System.out.print(d);  
    }  
}

private void aotujudge(double\[\] xy1, double\[\] xy2, double\[\] xy3, double\[\] xy4) {  
    double t1=(xy3\[0\]-xy1\[0\])\*(xy2\[1\]-xy1\[1\])-(xy3\[1\]-xy1\[1\])\*(xy2\[0\]-xy1\[0\]);  
    double t2=(xy3\[0\]-xy1\[0\])\*(xy4\[1\]-xy1\[1\])-(xy3\[1\]-xy1\[1\])\*(xy4\[0\]-xy1\[0\]);  
    double t3=(xy4\[0\]-xy2\[0\])\*(xy1\[1\]-xy2\[1\])-(xy4\[1\]-xy2\[1\])\*(xy1\[0\]-xy2\[0\]);  
    double t4=(xy4\[0\]-xy2\[0\])\*(xy3\[1\]-xy2\[1\])-(xy4\[1\]-xy2\[1\])\*(xy3\[0\]-xy2\[0\]);  
     if(t1\*t2<= 0.001 && t3\*t4 <= 0.001) {  
         System.out.print(true+" ");  
     }  
     else {  
         System.out.print(false+" ");  
     }  
}

4.第四个要求由于能力问题,但是也可以分享一下思路,首先判断直线与四边形(也可能是三角形)相交的交点数量,应该可以在网上查询资料,可以通过向量法来求直线是否与三角形或四边形相交。

5.第五个要求的思路是通过第一个点的横坐标和纵坐标来和另外三个或四个点的横坐标和纵坐标来相比较,这里比较麻烦的就是要选择出三个点或四个点之中的最大值和最小值,然后再与第一个点进行比较,在进行大致的推算来判断点是否在多边形内。

踩坑心得:通过前三个要求的代码,我发现每次都求解都需要判断四个点是否构成四边形,所以如果不好好看清楚题目的话,那就要每次都得写一连串的代码来实现判断,这就大大地增加了代码的复杂度,而且让自己疲于理清if-else的关系中。因此可以单独写一个方法来实现是否为四边形的判断,通过此方法来简化代码,可惜当我反应过来已经是结束后了。

1.农夫过河问题:一个农夫带着一匹狼、一只羊、一颗白菜要过河,河上只有一条船能够渡河,而且农夫每次最多只能带一个动物或物品过河。当农夫不在的时候狼会吃羊,羊会吃白菜。  请以代码为基础,将程序代码补充完整,实现农夫过河游戏功能:由用户选择角色过河,系统自动判断游戏的胜负:当出现有生物被吃掉的时候,游戏失败,所有角色都到了河的另一边,游戏成功。

原题目代码:

package 农夫过河;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Game game = new Game();
game.play();
}
}

(2) 游戏界面类,用于显示界面;

package 农夫过河;

public class GameGui {
public void menu()
{
/* 显示菜单 */
System.out.println("==================Please choose operation============");
System.out.println("\t==========1:Cross the river alone===========");
System.out.println("\t==========2:Cross the river with wolf=========");
System.out.println("\t==========3:Cross the river with sheep============");
System.out.println("\t==========4:Cross the river with cabbage==========");
System.out.println("\t==========0:Quit===============");
System.out.println("===================================================");
System.out.println("Input the number(0~4):");
}

public void showStatus(Farmer farmer, Wolf wolf, Sheep sheep, Cabbage cabbage) {  
    /\* 输出农夫、各种动物、物品的状态(生存、位置) \*/  
        farmer.showStatus();  
        wolf.showStatus();  
        sheep.showStatus();  
        cabbage.showStatus();  
    }  

}
(3) 游戏类,用于执行游戏;
package 农夫过河;

import java.util.Scanner;

public class Game {
Wolf wolf;
Sheep sheep;
Cabbage cabbage;
Farmer farmer;
//GameGui gui;

Game() {  
    wolf = new Wolf();  
    sheep = new Sheep();  
    cabbage = new Cabbage();  
    farmer = new Farmer();  
}

protected void play() {  
    Scanner input = new Scanner(System.in);  
    int choice = 0;            //用户输入选择  
    boolean gameOver=false,//游戏结束标志,默认为false,代表游戏进行中,未结束  
            win=false;     //游戏输赢标志,默认为false,代表未赢得游戏。  
    while(!gameOver)  
    {  
        GameGui.menu();  
        choice = input.nextInt();  
        switch(choice)  
        {  
            case 0: gameOver=true;  
                break;  
            case 1:/\* 农夫独自过河的处理 \*/  
                farmer.crossRiver=!( farmer.crossRiver);  
                break;  
            case 2:/\* 农夫带狼的处理 \*/  
                farmer.crossRiver=!( farmer.crossRiver);  
                wolf.crossRiver=!( wolf.crossRiver);  
                break;  
            case 3:/\* 农夫带羊的处理 \*/  
                farmer.crossRiver=!( farmer.crossRiver);  
                sheep.crossRiver=!( sheep.crossRiver);  
                break;  
            case 4:/\* 农夫带白菜的处理 \*/  
                farmer.crossRiver=!( farmer.crossRiver);  
                cabbage.crossRiver=!( cabbage.crossRiver);  
                break;  
        }  
        wolf.eatSheep(sheep);//狼吃羊,如果羊不在同一边,则吃不到,如果在同一边,羊被吃  
        sheep.eatCabbage(cabbage);//同上  
        GameGui.showStatus(farmer,wolf,sheep,cabbage);  
        gameOver = isGameOver();  
    }  
    win=this.hasWin();  
    if(win) {  
        System.out.println("game over: you win !");  
    }else {  
        System.out.println("game over: you lose !");  
    }  
    input.close();

}  
/\*  
 \* 判断游戏是否结束  
 \* 输入:无  
 \* 运算:羊、白菜任一实体被吃,游戏结束,或者狼、羊、白菜均未被吃且全部渡过河,游戏结束  
 \* 输出:游戏结束--返回true ,未结束--返回false  
 \*/  
public boolean isGameOver() {  
    if(sheep.isAlive==false||cabbage.isAlive==false) {  
        return true;  
    }  
    if(wolf.hasCross&&sheep.hasCross&&cabbage.hasCross) {  
        return true;  
    }  
    return false;  
}  
/\*  
 \* 判断游戏是否胜利  
 \* 前置条件:游戏结束  
 \* 输入:无  
 \* 运算:狼、羊、白菜均未被吃且全部渡过河,游戏胜利,否则失败  
 \* 输出:游戏胜利--返回true ,失败--返回false  
 \*/  
public boolean hasWin() {  
    if(sheep.isAlive==false||cabbage.isAlive==false) {  
        return false;  
    }  
    if(wolf.hasCross&&sheep.hasCross&&cabbage.hasCross) {  
        return true;  
    }else {  
        return false;  
    }  
}

}

由于本次实验是将已给的代码给补充完整,所以难度还先,我们可以将它复制到eclipse上,让后根据它的报错点来进行修改,在源代码的基础上写出Farmer,Wolf,Sheep和Cabbage类,最后再在各个类中补全要用到的一些方法。

2.改进:

(1)       对farmer,wolf,sheep,cabbage进行数据封装的改进,将属性隐藏。

(2)       增加Boat(船)类,设计船类的相应方法,并修改main方法中相关的代码,改进农夫带东西过河的功能,解决之前代码中存在的农夫带东西过河的判断问题。

(3)       为wolf,sheep 两个类添加带Stirng name参数的构造函数,当创建wolf,sheep对象时,假设输入了name参数,程序分别输出:

啊呜~~~我 *name* 狼又回来了

咩咩,我是可爱的小羊*name*

这次改进使得各个类中的属性都变成了private的私有变量,所以在其他类中都不能用它们,我们可以通过引用各个类中的方法来return那个要再别的地方用到的变量。另外,题目还要求增加一个Boat(船)类,而这个船类可以把它看成给农夫过河的一个媒介,通过它来 进行参数的传递。最后还要分别在Wolf类和Sheep类中加上name属性和Showname()来输出题目要求的内容。

3.继续改进:

(1)       为之前的类添加合适的父类。

(2)       为父类添加适合的属性和方法。并以此为基础修改原有的类,使之与添加的类构成继承关系。

(3)       使用多态改进整个代码,提高代码的复用性。

第三次改进需要用到继承和多态的知识,通过分析我们可以发现四个过河的对象类中都有许多相同的属性和方法,我们可以为这四个类写一个父类Process表示过河的过程类,然后在修改一下Game类中的对象的定义方式,通通都用Process来定义,之后再在Process类写下四个类都需要的方法,最后再在四个类中对父类的方法进行重写和覆盖。

两次改进后的代码如下:

public class Boat extends Process{

public Boat(Process farmer) {  
    farmer.CrossRiver();  
}

public Boat(Process farmer, Process dongxi) {  
    farmer.CrossRiver();  
    dongxi.CrossRiver();  
}

}

public class Process {

private boolean isAlive=true;  
private boolean hasCross=false;

public void Dead() {  
    isAlive=(!isAlive);  
}

public boolean Isalive() {  
    return isAlive;  
}

public void CrossRiver() {  
     hasCross=(!hasCross);  
}

public boolean HasCross() {  
    return hasCross;  
}

public void showStatus() {

}

public void eatSheep(Process sheep, Process farmer) {

}

public void eatCabbage(Process cabbage, Process farmer) {

}

}

public class Cabbage extends Process{

public void showStatus() {

    System.out.print("Cabbage is alive :"+super.Isalive()+"   ");  
    System.out.println("Cabbage has Cross  :"+super.HasCross());

}

}

public class Farmer extends Process{

public void showStatus() {  
    System.out.println("Farmer has Cross  :"+super.HasCross());  
}

}

public class Sheep extends Process{

private String name;

public Sheep(String name) {  
    this.name=name;  
    System.out.println("咩咩,我是可爱的小羊\*"+this.name+"\*");  
}

public void eatCabbage(Process cabbage,Process farmer) {

    if(cabbage.HasCross()==super.HasCross()&&super.HasCross()!=farmer.HasCross()) {  
        cabbage.Dead();  
    }

}

public void showStatus() {

    System.out.print("Sheep \*"+this.name+"\* is alive :"+super.Isalive()+"   ");  
    System.out.println("Sheep \*"+this.name+"\* has Cross :"+super.HasCross());

}

}

public class Wolf extends Process{

private String name;

public Wolf(String name) {  
    this.name=name;  
    System.out.println("啊呜~~~我 \*"+this.name+"\* 狼又回来了");  
}

public void eatSheep(Process sheep,Process farmer) {  
    if(sheep.HasCross()==super.HasCross()&&super.HasCross()!=farmer.HasCross()) {  
        sheep.Dead();  
    }  
}  
public void showStatus() {

    System.out.print("Wolf \*"+this.name+"\* is alive :"+true+"   ");  
    System.out.println("Wolf \*"+this.name+"\* has Cross :"+super.HasCross());

}

}

踩坑心得:起初我在做第一次改进时是在Game中定义了一个GameGui来应用GameGui中的一些菜单,但是这样对给出的代码有太大的改动,于是后知后觉才知道可以用static来将GameGui()中的方法静态化,这样就可以通过类名来直接引用方法,这样就不会用很大的改动。

  • 设计一个类表示平面直角坐标系上的点Point,私有属性分别为横坐标x与纵坐标y,数据类型均为实型数,除构造方法以及属性的getter与setter方法外,定义一个用于显示信息的方法display(),用来输出该坐标点的坐标信息,格式如下:(x,y),数值保留两位小数。为简化题目,其中,坐标点的取值范围设定为(0,200]。若输入有误,系统则直接输出Wrong Format

  • 设计一个类表示平面直角坐标系上的线Line,私有属性除了标识线段两端的点point1、point2外,还有一个字符串类型的color,用于表示该线段的颜色,同样,除构造方法以及属性的getter与setter方法外,定义一个用于计算该线段长度的方法getDistance(),还有一个用于显示信息的方法display(),用来输出线段的相关信息,输出格式如下:

          The line's color is:颜色值
          The line's begin point's Coordinate is:
          (x1,y1)
          The line's end point's Coordinate is:
          (x2,y2)
          The line's length is:长度值

这道题是一道看类图写代码的题目,其实题目难度不大,补全类中的方法和属性就也还行,做这种题需要我们对类图比较熟悉,对图中的一些符号和箭头有一定的了解。还有在写题目时要头脑清晰,理清各个类之间的关系,还有就是要善于借助一些编程软件来帮助你构造函数。

类图如下:

通过以上的类图可以发现Point类和Line类都和主类相关的,所以根据类图可写出代码如下:

import java.util.Scanner;

public class Main{
public static void main(String []args) {
Scanner in=new Scanner (System.in);
double x1=in.nextDouble();
double y1=in.nextDouble();
double x2=in.nextDouble();
double y2=in.nextDouble();
Line1 line = new Line1(new Point(x1,y1),new Point(x2,y2),in.next());
line.display();
}

}
class Point {
private double x;
private double y;

public Point(){

}

public Point(double x,double y){  
    this.setX(x);  
    this.setY(y);  
}

public void setX( double x) {  
    this.x=x;  
}

public double getX() {  
    return (this.x);  
}

public void setY( double y) {  
    this.y=y;  
}

public double getY() {  
    return (this.y);  
}

public void display(){  
    if(x<0||x>200||y<0||y>200) {  
        System.out.print("Wrong Format");  
    }  
    else {  
        String x1=String.format("%.2f", x);  
        String y2=String.format("%.2f", y);  
        System.out.println("("+x1+","+y2+")");  
    }  
}

}
class Line1{
private Point point1;
private Point point2;
private String color;

public Line1(Point p1,Point p2,String color){  
    this.setPoint1(p1);  
    this.setPoint2(p2);  
    this.setColor(color);  
}

public Point getPoint1() {  
    return (this.point2);  
}

public void setPoint1(Point point1) {  
    this.point1=point1;  
}

public Point getPoint2() {  
    return (this.point2);  
}

public void setPoint2(Point point2) {  
    this.point2=point2;  
}

public String getColor() {  
    return (this.color);  
}

public void setColor(String color) {  
    this.color=color;  
}

public double getDistance() {  
    double distant;  
    distant = Math.sqrt(Math.pow(point1.getX()-point2.getX(), 2)+Math.pow(point1.getY()-point2.getY(), 2));  
    return distant;  
}

public void display() {  
    if(point1.getX()<0||point1.getX()>200||point1.getY()<0||point1.getY()>200) {  
        point1.display();  
    }  
    else if(this.point2.getX()<0||this.point2.getX()>200||point2.getY()<0||point2.getY()>200){  
        point2.display();  
    }  
    else {  
        System.out.println("The line's color is:"+color);  
        System.out.println("The line's begin point's Coordinate is:");  
        point1.display();  
        System.out.println("The line's end point's Coordinate is:");  
        point2.display();  
        String dis=String.format("%.2f",this.getDistance());  
        System.out.println("The line's length is:"+dis);

    }

}  

}

踩坑心得:做完这道题,我才发现细心是多麽重要。我们在写代码时通常习惯将一些相同的代码复制粘贴到某处,这样做固然可以节省时间,但是也要注意变量的名字,我就是因为复制了一个Point1在本应该是写Point2的地方上,结果粗心忘了改过来,结果在运行是Point2老是报错为空,于是我又花了大把时间去debug和肉眼查找,浪费了很多时间,因为这是考试,所以这也影响了之后的心态,仔细是那么重要!。

在“点与线(类设计)”题目基础上,对题目的类设计进行重构,以实现继承与多态的技术性需求。

  • 对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。
  • 再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:The Plane's color is:颜色
  • 在主方法内,定义两个Point(线段的起点和终点)对象、一个Line对象和一个Plane对象,依次从键盘输入两个Point对象的起点、终点坐标和颜色值(Line对象和Plane对象颜色相同),然后定义一个Element类的引用,分别使用该引用调用以上四个对象的display()方法,从而实现多态特性。

这道题是在第一题上的升级版,要我们对上一题通过继承和多态来进行重构,这里还要求创建一个抽象类父类ELement和抽象display()方法在该方法中进行声明,而且还加入了一个子类Plane来进行输出面对颜色。所以,这道题简单来说就是改进第一题,并不需要改变太多代码,只需要添加几个类和个别抽象方法。

类图如下:

代码如下:

import java.util.Scanner;

public class Main{
public static void main(String []args) {
Scanner in=new Scanner (System.in);
double x1=in.nextDouble();
double y1=in.nextDouble();
double x2=in.nextDouble();
double y2=in.nextDouble();

    if(x1>0&&x1<=200&&y1>0&&y1<=200&&x2>0&&x2<=200&&y2>0&&y2<=200) {  
        Point point1 = new Point(x1,y1);  
        Point point2 = new Point(x2,y2);  
        Plane plane = new Plane(in.next());  
        Line line = new Line(point1,point2);  
        Element element;  
        element = point1;  
        element.display();  
        element = point2;  
         System.out.println("The line's color is:"+plane.color);  
        element.display();  
        element = line;  
        element.display();  
        element = plane;  
        element.display();  
    }  
    else {  
        System.out.print("Wrong Format");  
    }

}

}
abstract class Element{

public abstract display() ;

}
class Plane extends Element{

private String color;

public Plane(){

}

public Plane(String color) {  
    this.setColor(color);  
}

public String getColor() {  
    return (this.color);  
}

public void setColor(String color) {  
    this.color=color;  
} 

public void display() {  
    System.out.println("The Plane's color is:"+color);  
}

}
class Point extends Element{
private double x;
private double y;

public Point(){

}

public Point(double x,double y){  
    this.setX(x);  
    this.setY(y);  
}

public void setX( double x) {  
    this.x=x;  
}

public double getX() {  
    return (this.x);  
}

public void setY( double y) {  
    this.y=y;  
}

public double getY() {  
    return (this.y);  
}

public void display(){  
    String x1=String.format("%.2f", x);  
    String y2=String.format("%.2f", y);  
    System.out.println("("+x1+","+y2+")");  
}

}
class Line extends Element{
Point point1;
Point point2;

public Line(){

}

public Line(Point point12,Point point22){  
    this.setPoint1(point12);  
    this.setPoint2(point22);  
}

public Point getPoint1() {  
    return (this.point2);  
}

public void setPoint1(Point point1) {  
    this.point1=point1;  
}

public Point getPoint2() {  
    return (this.point2);  
}

public void setPoint2(Point point2) {  
    this.point2=point2;  
}

public double getDistance() {  
    double distant;  
    distant = Math.sqrt(Math.pow(point1.getX()-point2.getX(), 2)+Math.pow(point1.getY()-point2.getY(), 2));  
    return distant;  
}

public void display() {

        System.out.println("The line's begin point's Coordinate is:");  
        point1.display();  
        System.out.println("The line's end point's Coordinate is:");  
        point2.display();  
        String dis=String.format("%.2f",this.getDistance());  
        System.out.println("The line's length is:"+dis);  
}

}

踩坑心得:这道题的易错点就是在抽象父类中的display()方法也要用抽象方法来实现。另外要分清楚点的颜色和线的颜色的输出位置,不然在这又会浪费时间。

在“点与线(继承与多态)”题目基础上,对题目的类设计进行重构,增加容器类保存点、线、面对象,并对该容器进行相应增、删、遍历操作。

  • 在原有类设计的基础上,增加一个GeometryObject容器类,其属性为ArrayList<Element>类型的对象(若不了解泛型,可以不使用<Element>
  • 增加该类的add()方法及remove(int index)方法,其功能分别为向容器中增加对象及删除第index - 1(ArrayList中index>=0)个对象
  • 在主方法中,用户循环输入要进行的操作(choice∈[0,4]),其含义如下:
    • 1:向容器中增加Point对象
    • 2:向容器中增加Line对象
    • 3:向容器中增加Plane对象
    • 4:删除容器中第index - 1个数据,若index数据非法,则无视此操作
    • 0:输入结束

这道题要用到容器类这方面的知识,但是当时并没有学到那块,所以在考试的时候并没有写出来这题。还是根据类图来分析一下思路:

类图如下:

光看这个类图那么多虚实箭头和各种类,确实比较复杂,但是有了之前的两道题的经验,我们要定义一个ArrayList的容器来进行增加Point对象,增加Line对象和Plane对象。其中这三种对象应该通过add()方法来进行添加,还有就是通过remove()方法来进行删除操作。还要在第二题的基础上加入循环操作来进行选择执行的操作,分析结束。

总结

  通过这几次的练习和考试,我学到了运用继承来进行简化代码,通过正则表达式来查找和判断字符串(只是学了一点皮毛)。这次考试也让我学会在有限的时间里一定要仔细,不能急于求成,要有一个好心态,控制好时间。另外通过这几次作业和实验,我也感到自己的能力已经远远落后于其他同学,我感觉自己愈来愈赶不上老师的进度,我对于面向对象程序设计这门课也是日渐感到陌生,面对自己写不出来的题目,我会莫名地在心里窝火和骂自己,可是这有什么用呢?自己缺乏练习,所以才对很多用法不熟,因为不熟才会在考试中花大把时间来写第一题;因为不熟才会粗心。。。。。。这几次的实验和考试也是一次对自己的一个警醒吧。还是得多做题,上课认真,合理分配各科的时间,多花时间在专业课上。努力做到独立思考,同时还要加强自己写代码的能力。