package xiang;
import java.io.IOException;
import java.util.*;
/**
* class Visit 用来处理人机交互的命令
*
*/
public class Visit {
protected Spot location;// 当前所在地点
protected Building bd = new Building();
/* 地点描述 Key是地点描述description 以及地点 Value是地点Spot之间的映射Map */
private Map spotDescriptonMap = new HashMap();
final static int where = 0;// 显示当前在什么地方
final static int list = 1;// 列出当前位置附近的地点或者物品
final static int gotos = 2;// 到另一个地点
final static int look = 3;// 查询某个物品是否在当前地点
final static int help = 4;// 命令行提示,列出各种命令
public Visit() {
location = bd.getSpots()[0];// 当前位置
mapSpotDescriptioToSpot();
}
/**
* 实现 spotDescriptio到spot的映射
*
* @param sp
* 代表地点数组
*/
private void mapSpotDescriptioToSpot() {
Spot[] sp = bd.getSpots();
int n = sp.length;
for (int i = 0; i < n; i++) {
spotDescriptonMap.put(sp[i].description, sp[i]);
}
}
/**
* 获取人机交互的命令
*
*/
public String getCommand() {
byte[] b = new byte[20];
String s = new String();
try {
int n = System.in.read(b);// 回车换行也读到了,所以下面要减2
s = new String(b, 0, n - 2);
s = s.trim();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return s;
}
/**
* 处理控制台输入的命令s
*/
public boolean processCommand(String s) {
boolean bl = true;
if (!(s.compareTo("") == 0)) {
int n = s.indexOf(' ');
if (n == -1) {
if (s.compareToIgnoreCase("where") == 0) {
processCommand(where);
} else if (s.compareToIgnoreCase("help") == 0) {
processCommand(help);
} else if (s.compareToIgnoreCase("list") == 0) {
processCommand(list);
} else
bl = false;
} else {
String s1 = s.substring(0, s.indexOf(' '));
String s2 = s.substring(s.indexOf(' ') + 1);
s2=s2.trim();
if (s1.compareToIgnoreCase("goto") == 0) {
bl = processCommand(gotos, s2);
} else if (s1.compareToIgnoreCase("list") == 0) {
bl = processCommand(list, s2);
} else if (s1.compareToIgnoreCase("look") == 0) {
bl = processCommand(look, s2);
} else
bl = false;
}
}
return bl;
}
/**
* 处理各种命令 双参数
*
* @param command
* 代表命令,例如look,goto,where
* @param obj
* 代表物品或者地点 比如 电脑,电视,登记表
*/
private boolean processCommand(int command, String obj) {
if (command == gotos) {
/* 不包含这个地点 */
if (!spotDescriptonMap.containsKey(obj))
System.out.println(obj + " is not in the building");
else {
Spot sp = (Spot) spotDescriptonMap.get(obj);// 类型转换
/* 原地 */
if (sp == location)
System.out.println("You are at " + location.description
+ " now.");
/* 不能直接到这个地点,当前位置与obj不相邻 */
else if (!location.adjacentList.contains(sp))
processGotoCommand(sp);
/* 当前位置移到obj */
else {
System.out.println(obj);
location = sp;
}
}
}
if (command == list)
return processListCommand(obj);
/* 当前地点有没有obj这个物品 */
else if (command == look) {
if (!location.goodsList.contains(obj)) {
System.out.println(obj + " is not at " + location.description);
} else {
System.out.println(obj + " is at " + location.description);
}
}
return true;
}
/**
* 到一个不相邻的地点
*
* @param sp
* 要去的地点
*/
private void processGotoCommand(Spot sp) {
int n = bd.getSpotNumber();
float[][] cost = bd.getDistance();/* 相邻地点之间的距离 */
float[] dist = new float[n];/* 到obj的距离 */
int[][] path = new int[n][n];/* 到obj的路径 */
Spot[] spots = bd.getSpots();/* 获取所有地点 */
int v = location.id;/* 当前地点的编号 */
int w = sp.id;/* obj的编号 */
shortestPath(cost, v, n, dist, path);
float distance = dist[w];
if (distance == Building.NOTAdjacent) {/* 不可达 */
System.out.println(sp.description + " cannot be reached from "
+ location.description);
} else {
int length = 0;/* 从v到w中间经历地点个数 */
while (path[w][length] != -1)
length++;
int i = 0;
for (i = 0; i < length - 1; i++) {
System.out.print(spots[path[w][i]].description + "->");
}
System.out.println(spots[path[w][i]].description);
location = spots[path[w][i]];
}
}
/**
*
* @param obj
* goods spots allspots
* @return 参数是否合适
*/
private boolean processListCommand(String obj) {
/* 列出当地物品 */
if (obj.compareToIgnoreCase("goods") == 0) {
Iterator itr = location.goodsList.iterator();
while (itr.hasNext()) {
Object element = itr.next();
System.out.print(element + " ");
}
System.out.println();
return true;
}
/* 列出附近地点 */
else if (obj.compareToIgnoreCase("spots") == 0) {
Iterator itr = location.adjacentList.iterator();
while (itr.hasNext()) {
Spot element = (Spot) itr.next();
System.out.print(element.description + " ");
}
System.out.println();
return true;
}
/* 列出大厦内所有地点 */
else if (obj.compareToIgnoreCase("allspots") == 0) {
Spot[] spots = bd.getSpots();
int n = spots.length;
for (int i = 0; i < n; i++) {
System.out.print(spots[i].description + " ");
}
System.out.println();
return true;
} else
return false;
}
/**
* 处理各种命令 单参数
*
* @param command
* 代表命令,例如list,where
*/
private void processCommand(int command) {
switch (command) {
case where:/* 显示当前位置 */
System.out.println(location.description);
break;
case list: {/* 列出当地物品 */
Iterator itr = location.goodsList.iterator();
while (itr.hasNext()) {
Object element = itr.next();
System.out.print(element + " ");
}
System.out.println();
break;
}
case help: {/* 显示帮助命令 */
processHelpCommand();
break;
}
default:
break;
}
}
/**
* 处理help命令
*
*/
private void processHelpCommand() {
System.out.println("where 显示当前在什么地方");
System.out.println("list 列出当前位置的物品");
System.out.println("list allspots 列出大厦内所有地点");
System.out.println("list spots 列出当前位置附近的地点");
System.out.println("list goods 列出当前位置的物品");
System.out.println("goto someplace 到另一个地点");
System.out.println("look somegoods 查询某个物品是否在当前地点");
System.out.println("help 命令行帮助");
System.out.println("exit 退出命令行");
}
/**
* 单源最短路径的Dijstra算法
*
* @param v
* 源
* @param cost
* 权值
* @param n
* 结点个数
* @param dist
* v到各顶点的距离
* @param path
* 路径
*/
static void shortestPath(float[][] cost, int v, int n, float[] dist,
int[][] path) {
int i, w, u, count;
int[] pos = new int[n];
int[] s = new int[n];
for (i = 0; i < n; i++) {
s[i] = 0;
dist[i] = cost[v][i];
path[i][0] = v;
for (int j = 1; j < n; j++)
path[i][j] = -1;/* 标记而已 */
pos[i] = 0;/* 第i条路径的位置计数器 */
}
s[v] = 1;
count = 1;
while (count < n) {
u = minDistance(s, dist);
s[u] = 1;
path[u][++pos[u]] = u;/* 先自加后操作 */
count++;
/* 更新 dist数组 */
for (w = 0; w < n; w++) {
if (s[w] == 0 && cost[u][w] < Float.MAX_VALUE
&& dist[u] + cost[u][w] < dist[w]) {
dist[w] = dist[u] + cost[u][w];
pos[w] = pos[u];/* 拷贝 */
for (i = 0; i <= pos[u]; i++)
path[w][i] = path[u][i];
}
}
}
}
/**
* @return u 利用s和dist在尚未找到最短路径的顶点中确定一个与v最接近的顶点
*
*/
static int minDistance(int[] s, float[] dist) {
float min = Float.MAX_VALUE;
int n = s.length;
int u = n;
for (i