假想你在火星探索团队中负责软件开发。现在你要给登陆火星的探索小车编写控制程序,根据地球发送的控制指令来控制火星车的行动。
火星车收到的指令分为:
初始化信息:火星车的降落地点(x, y)和朝向(N, S, E, W)信息;
移动指令:火星车可以前进(M),一次移动X格;
移动指令:火星车可以前进(B),一次移动X格;
转向指令:火星车可以左转90度(L)或右转90度(R)。
由于地球和火星之间的距离很远,指令必须批量发送,火星车执行完整批指令之后,再回报自己所在的位置坐标和朝向。
package com.thoughtworks.b_mars_rover;
import java.util.ArrayList;
import java.util.List;
public class Run {
public static void main(String[] args) {
// Instruct (指令类型,角度,移动距离)
List<Instruct> instructs = new ArrayList<>();
instructs.add(new Instruct(InstructType.MOVE, 0, 4));
instructs.add(new Instruct(InstructType.BACK, 0, 4));
instructs.add(new Instruct(InstructType.TURN_RIGHT, 37, 0));
instructs.add(new Instruct(InstructType.MOVE, 0, 5));
instructs.add(new Instruct(InstructType.BACK, 0, 5));
instructs.add(new Instruct(InstructType.TURN_LEFT, 164, 5));
instructs.add(new Instruct(InstructType.MOVE, 0, 5));
instructs.add(new Instruct(InstructType.BACK, 0, 5));
//初始化小车位置 x,y,朝向,顺时针角度
MarsRover marsRover = new MarsRover(0, 0, "N", 0);
System.out.println("初始化:小车朝向:"+marsRover.getFaceTo()+"----小车角度:"+marsRover.getAngle()+"---小车X轴位置:"+marsRover.getX()+"---小车Y轴距离:"+marsRover.getY());
for (Instruct instruct : instructs) {
if (instruct.getInstructType() == InstructType.BACK||instruct.getInstructType() == InstructType.MOVE) {
marsRover.move(instruct);
} else {
marsRover.wheel(instruct);
}
System.out.println("小车朝向:"+marsRover.getFaceTo()+"----小车角度:"+marsRover.getAngle()+"---小车X轴位置:"+marsRover.getX()+"---小车Y轴距离:"+marsRover.getY());
}
}
}
package com.thoughtworks.b_mars_rover;
import com.thoughtworks.b_mars_rover.move.MoveEnum;
import com.thoughtworks.b_mars_rover.move.MoveRule;
import com.thoughtworks.b_mars_rover.move.MoveRuleDispatchCentre;
import lombok.Data;
/**
* 探测车x,y,朝向,角度
*/
@Data
public class MarsRover {
private final static String allDirection = "NESW";
private double x;
private double y;
private String faceTo;
/**
* 角度为当前方向的顺时针角度
*/
private double angle;
public MarsRover(double x, double y, String faceTo, double angle) {
this.x = x;
this.y = y;
this.faceTo = faceTo;
this.angle = angle;
}
//小车转弯
public void wheel(Instruct wheelInstruct) {
//增大一圈,避免为负
double newAngel = this.getAngle() + wheelInstruct.getAngle();
/**
* 取探测车朝向
* >=0时取90的余数与探险车的索引相加
* <0时取90的余数与探险车的索引相减
*/
this.faceTo = newAngel >= 0 ? String.valueOf(allDirection.charAt((allDirection.indexOf(this.faceTo) + (int) ((newAngel + 360) / 90)) % 4)) :
String.valueOf(allDirection.charAt(((allDirection.indexOf(this.faceTo) + (int) (newAngel + 360) / 90) + 4) % 4));
this.angle = (newAngel + 360) % 90;
}
// 小车移动
public void move(Instruct instruct) {
MoveRule moveRule = null;
if (instruct.getInstructType() == InstructType.MOVE) {
moveRule = MoveRuleDispatchCentre.getMoveRule(MoveEnum.getInstance(this.getFaceTo()));
} else {
moveRule = MoveRuleDispatchCentre.getMoveRule(MoveEnum.BACK);
}
instruct.xyMoveDistance(this);
moveRule.move(instruct, this);
}
}
package com.thoughtworks.b_mars_rover;
import lombok.Getter;
/**
* 转向枚举
*/
public enum InstructType {
TURN_LEFT("L"), TURN_RIGHT("R"), MOVE("M"), BACK("B");
@Getter
private String InstructType;
InstructType(String instructType) {
InstructType = instructType;
}
public static InstructType getInstance(String instructType) {
if (TURN_LEFT.getInstructType().equals(instructType)) {
return TURN_LEFT;
}
return TURN_RIGHT;
}
}
package com.thoughtworks.b_mars_rover;
import com.thoughtworks.b_mars_rover.move.MoveEnum;
import lombok.Data;
/**
* 指令对象
*/
@Data
public class Instruct {
private InstructType instructType;
private double angle;
private double moveDistance;
private double xMoveDistance;
private double yMoveDistance;
public double getRealAngel(InstructType instructType, double angle) {
/**
* 转向大于360度,取余数
*/
angle = Math.abs(angle) >= 360 ? angle % 360 : angle;
/**
* 左转为负数,右转为正数
*/
return instructType == InstructType.TURN_LEFT ? -angle : angle;
}
/**
* 移动小车之前必须先计算小车位移的X和Y距离
*
* @param marsRover
*/
public void xyMoveDistance(MarsRover marsRover) {
if (MoveEnum.getInstance(marsRover.getFaceTo()) == MoveEnum.EAST || MoveEnum.getInstance(marsRover.getFaceTo()) == MoveEnum.WEST) {
moveToEastAndWest(marsRover);
} else {
moveToNorthAndSorth(marsRover);
}
}
private void moveToNorthAndSorth(MarsRover marsRover) {
this.setYMoveDistance(Math.cos(Math.toRadians(marsRover.getAngle())) * this.getMoveDistance());
this.setXMoveDistance(Math.sin(Math.toRadians(marsRover.getAngle())) * this.getMoveDistance());
}
private void moveToEastAndWest(MarsRover marsRover) {
this.setXMoveDistance(Math.cos(Math.toRadians(marsRover.getAngle())) * this.getMoveDistance());
this.setYMoveDistance(Math.sin(Math.toRadians(marsRover.getAngle())) * this.getMoveDistance());
}
public Instruct(InstructType instructType, double angle, double moveDistance) {
this.instructType = instructType;
this.angle = getRealAngel(instructType, angle);
this.moveDistance = moveDistance;
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.InstructType;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 后退
*/
public class BackMove implements MoveRule {
@Override
public void move(Instruct moveInstruct, MarsRover marsRover) {
moveInstruct.setXMoveDistance(0 - moveInstruct.getXMoveDistance());
moveInstruct.setYMoveDistance(0 - moveInstruct.getYMoveDistance());
moveInstruct.setInstructType(InstructType.MOVE);
MoveRule moveRule = MoveRuleDispatchCentre.getMoveRule(MoveEnum.getInstance(marsRover.getFaceTo()));
moveRule.move(moveInstruct, marsRover);
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 小车朝向E到S
*/
public class EastMove implements MoveRule {
public static void main(String[] args) {
System.out.println(Math.cos(Math.toRadians(37)) * 5);
}
@Override
public void move(Instruct eastInstruct, MarsRover marsRover) {
marsRover.setX(marsRover.getX()+eastInstruct.getXMoveDistance());
marsRover.setY(marsRover.getY()-eastInstruct.getYMoveDistance());
}
}
package com.thoughtworks.b_mars_rover.move;
/**
* 移动规则枚举
*/
public enum MoveEnum {
NORTH("N"), WEST("E"), SORTH("S"), EAST("W"), BACK("B");
private String faceTo;
MoveEnum(String faceTo) {
this.faceTo = faceTo;
}
public static MoveEnum getInstance(String faceTo) {
switch (faceTo) {
case "N":
return NORTH;
case "E":
return EAST;
case "S":
return SORTH;
case "W":
return WEST;
default: {
return BACK;
}
}
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 移动规则父类
*/
public interface MoveRule {
void move(Instruct moveInstruct, MarsRover marsRover);
}
package com.thoughtworks.b_mars_rover.move;
import java.util.HashMap;
import java.util.Map;
public class MoveRuleDispatchCentre {
private static Map<MoveEnum, MoveRule> moveTypes = new HashMap<>();
static {
moveTypes.put(MoveEnum.NORTH, new NorthMove());
moveTypes.put(MoveEnum.WEST, new EastMove());
moveTypes.put(MoveEnum.SORTH, new SouthMove());
moveTypes.put(MoveEnum.EAST, new EastMove());
moveTypes.put(MoveEnum.BACK, new BackMove());
}
public static MoveRule getMoveRule(MoveEnum moveEnum) {
return moveTypes.get(moveEnum);
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 小车朝向N到E
*/
public class NorthMove implements MoveRule {
@Override
public void move(Instruct northInstruct, MarsRover marsRover) {
marsRover.setX(marsRover.getX()+northInstruct.getXMoveDistance());
marsRover.setY(marsRover.getY()+northInstruct.getYMoveDistance());
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 小车朝向S到W
*/
public class SouthMove implements MoveRule {
@Override
public void move(Instruct sorthInstruct, MarsRover marsRover) {
marsRover.setX(marsRover.getX()-sorthInstruct.getXMoveDistance());
marsRover.setY(marsRover.getY()-sorthInstruct.getYMoveDistance());
}
}
package com.thoughtworks.b_mars_rover.move;
import com.thoughtworks.b_mars_rover.Instruct;
import com.thoughtworks.b_mars_rover.MarsRover;
/**
* 小车朝向W到N
*/
public class WestMove implements MoveRule {
@Override
public void move(Instruct westInstruct, MarsRover marsRover) {
marsRover.setX(marsRover.getX()-westInstruct.getXMoveDistance());
marsRover.setY(marsRover.getY()+westInstruct.getYMoveDistance());
}
}