构建一个地图,
1.需要一个世界类,包含两个属性,一个图例属性,一个存储地图的属性。
2.需要一个地图类,地图类封装保存,取出地图元素的方法,以及存储地图。
一个格子类,该类为该格子,x,y坐标。
3.动物类,保存动物能用方向等信息。
流程:给世界类输入地图和图例(对象),1,世界类保存输入的地图为地图类,2,保存图例。通过一个foreach函数给该世界对象里的地图属性设置上每个元素,通过一个elementfromchar函数把非空的格子设置成动物类。
给世界添加了以一个属性tostring,获取每个地图类的格子元素,通过charfromelement函数输出成字符串。
4,添加一个view类为小动物的可视范围。该类会在世界类调用turn方法里面的letact方法时调用,也就是在动物移动的时候的才会去看往哪个方向可以移动。
整个过程大概是这样:通过传入地图字符串和图例,构建一个世界类的对象,世界类对象world有两个属性,grid是一个地图类,用来保存地图,legend存储图例对象。在world构造函数中会执行一个地图类(三个属性和四个方法,属性分别为space地图数组,为一维数组,另外2个为地图的宽和高,get方法,读取某个位置字符,set设置某个位置的字符,isinside方法判断该位置是否出界,并且实现了一个自己的forEach方法,目的是顶一个遍历grid的方法),可以使用call传递context)的方法,根据地图字符串设置好这个地图类,使用turn方法让world进行移动,移动规则为首先找到所有的动物即圆圈,根据已经建好的动物类的方法,使用worldletact方法让其移动,未来避免重复移动,在每次的移动中调用动物的act方法,调用的同时传入一个该位置的view类,同的view的方法检查可以移动的位置,移动是随机移动,移动方向根据view的look查看是否可以移动,不能的话找一个空位置移动,然后通过world tostring打印输出。
var plan = [
"############################",
"# # # o ##",
"# #",
"# ##### #",
"## # # ## #",
"### ## # #",
"# ### # #",
"# #### #",
"# ## o #",
"# o # o ### #",
"# # #",
"############################"];
function Vector(x,y){
this.x=x;
this.y=y;
}
Vector.prototype.plus=function (other) {
return new Vector(this.x+other.x,this.y+other.y);
};
//网格类
function Grid(width,height){
this.space = new Array(width*height);
this.width=width;
this.height=height;
}
Grid.prototype.isInside=function(vector){
return vector.x >=0 && vector.x < this.width &&
vector.y >=0 && vector.y < this.height;
};
Grid.prototype.get=function(vector){
return this.space[vector.x + (vector.y * this.width)];
}
Grid.prototype.set=function(vector,value){
this.space[vector.x + vector.y * this.width]=value;
}
Grid.prototype.forEach=function(f,context){
for(var y=0;y<this.height;y++){
for(var x=0;x<this.width;x++){
var value=this.space[x + y * this.width];//一会看一下这里的值,怎么处理的#
if(value!=null)
{
console.log(value);
f.call(context, value, new Vector(x,y));
}
}
}
}
var grid=new Grid(5,5);
grid.set(new Vector(1,2),"X");
console.log(grid);
//映射方向
var directions = {
"n": new Vector( 0, -1),
"ne": new Vector( 1, -1),
"e": new Vector( 1, 0),
"se": new Vector( 1, 1),
"s": new Vector( 0, 1),
"sw": new Vector(-1, 1),
"w": new Vector(-1, 0),
"nw": new Vector(-1, -1)
};
//蠢萌小动物对象
function randomElement(array){
return array[Math.floor(Math.random()*array.length)];
}
var directionNames = "n ne e se s sw w nw".split(" ");
function BouncingCritter(){
this.direction = randomElement(directionNames);
};
BouncingCritter.prototype.act=function(view){
if(view.look(this.direction)!=" ")
this.direction = view.find(" ") || "s";
return {type: "move", direction : this.direction};
};
function elementFromChar(legend, ch){
if(ch == " ")
return null;
var element = new legend[ch]();//这里是创建类
element.origiChar=ch;
return element;
}
//World对象
function World(map,legend){
var grid = new Grid(map[0].length, map.length);
this.grid = grid;
this.legend = legend;//图例对象
map.forEach(function(line, y){
for(var x=0;x<line.length;x++){
grid.set(new Vector(x,y),elementFromChar(legend,line[x]));//这里是无法使用this.grid的
}
});
}
//Wall对象占据空间
function Wall(){}
//转化字符串
function charFromElement(element){
if(element == null) return " ";
else return element.origiChar;
}
World.prototype.toString = function(){
var output="";
for(var y=0;y<this.grid.height;y++){
for(var x=0;x<this.grid.width;x++){
var element = this.grid.get(new Vector(x, y));
output += charFromElement(element);
}
output+="\n";
}
return output;
}
//world 添加turn方法
World.prototype.turn = function(){
var acted = [];
this.grid.forEach(function(critter,vector){
console.log(critter);
if(critter.act && acted.indexOf(critter)==-1){
acted.push(critter);
this.letAct(critter,vector);
}
},this);
};
World.prototype.letAct=function(critter, vector){
var action = critter.act(new View(this, vector));
if(action && action.type == "move"){
var dest = this.checkDestination(action, vector);
if(dest && this.grid.get(dest) == null){
this.grid.set(vector, null);
this.grid.set(dest, critter);
}
}
};
World.prototype.checkDestination = function(action, vector){
if(directions.hasOwnProperty(action.direction)){
var dest=vector.plus(directions[action.direction]);
if(this.grid.isInside(dest))
return dest;
}
}
var world=new World(plan,{'#':Wall,
"o":BouncingCritter});
console.log(world.toString());
//定义一个View类为小动物的可视范围
function View(world,vector){
this.world = world;
this.vector = vector;
}
View.prototype.look=function(dir){
var target = this.vector.plus(directions[dir]);
if(this.world.grid.isInside(target))
return charFromElement(this.world.grid.get(target));
else return '#';
};
View.prototype.findAll=function(ch){
var found=[];
for(var dir in directions)
if(this.look(dir) == ch)
found.push(dir);
return found;
}
View.prototype.find=function(ch){
var found=this.findAll(ch);
if(found.length == 0) return null;
return randomElement(found);
};
for(var i=0;i<5;i++){
world.turn();
console.log(world.toString());
}