`
superobin
  • 浏览: 9554 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

带简单AI的俄罗斯方块

阅读更多
<html>
<head>
<title>TETRIS AI</title>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="MSThemeCompatible" content="yes" />
<script type="text/javascript" src="./tetrisai.js"></script>
<style>
.fill {
	width: 2px;
	height: 2px;
	background-color: #666666;
}

.blank {
	width: 6px;
	height: 6px;
	background-color: #FFFFFF;
}

.active {
	width: 6px;
	height: 6px;
	background-color: #3399FF;
}

.pad {
	background-color: #EEEEEE
}
.error {
	width: 6px;
	height: 6px;
	background-color: #FF0000
}
.block {
	width: 6px;
	height: 6px;
	display:none;
}
</style>
</head>
<body onload="load()" onkeydown="EventDispatcher()">
<table>
	<tr>
		<td>
		<div id="render1"></div>
		<input type="button" value="start" onclick="ctrl1.start();">
		<input type="button" value="stop" onclick="ctrl1.stop();">
		<input type="button" value="clear" onclick="ctrl1.clear();">
		</td>
		<td>
<!--		<div id="render2"></div>		-->
<!--		<input type="button" value="start" onclick="ctrl2.start();">-->
<!--		<input type="button" value="stop" onclick="ctrl2.stop();">-->
<!--		<input type="button" value="clear" onclick="ctrl2.clear();">-->
<!--		</td>-->
	</tr>
</table>
</body>
</html>


tetrisai.js
/**************************
 * Tetris AI Refine Edition
 * @author FuLi
 **************************/

/*
 * The container of the basic methods of the Tetris.
 */
TetrisUtil = {
	/*
	 * Copy all the properties of source into destination.
	 */
	mix : function(/* mixed */destination, /* mixed */source) {
		for ( var property in source) {
			destination[property] = source[property];
		}
		return destination;
	},
	/*
	 * Returns a new class of JavaScript that the default initialize method is
	 * this.initialize.
	 */
	createClass : function() {
		return function() {
			this.initialize.apply(this, arguments);
		}
	},
	/*
	 * Returns a clone array of pure data(string/number),without any references.
	 */
	cloneAry : function(/* Array */aryin) {
		var ret = [];
		var length = aryin.length;
		for ( var i = 0; i < length; i++) {
			var element;
			if (typeof aryin == "object" && aryin[i].constructor == Array) {
				element = arguments.callee(aryin[i]);
			} else {
				element = aryin[i];
			}
			ret.push(element);
		}
		return ret;
	},
	/*
	 * Returns a clone array of pure number without any references, very fast in
	 * IE.
	 */
	cloneSimpleAry : function(/**/aryin) {
		return eval("([" + aryin.toString() + "])");
	},
	/*
	 * Returns the really array object from a fake array(object set)
	 */
	toArray : function(/* */ary) {
		var ret = [];
		for ( var i = 0; i < ary.length; i++) {
			ret.push(ary[i]);
		}
		return ret;
	},
	/*
	 * Returns a new function that content is the first argument,scopee is the
	 * second argument,and the others is the argument to bind to the given
	 * function.
	 */
	bind : function(/* Function,obj0[,obj1...] */) {
		var args = TetrisUtil.toArray(arguments);
		var __method = args.shift();
		var object = args.shift();
		return function() {
			return __method.apply(object, args.concat(TetrisUtil.toArray(arguments)));
		}
	},
	/*
	 * Returns the sum of the input array,which is a set of pure number.
	 */
	sumAry : function(/* Array */ary) {
		var ret = 0;
		for ( var i = 0; i < ary.length; i++) {
			ret += ary[i];
		}
		return ret;
	},
	/*
	 * Inputs a 2d array[x][y],and returns sum x.
	 */
	sumAryX : function(/* Array[][] */ary2d,/* int */rowIndex) {
		var sum = 0;
		for ( var i = 0; i < ary2d.length; i++) {
			sum += ary2d[i][rowIndex];
		}
		return sum;
	},
	/*
	 * Empty function for some default function references.
	 */
	emptyFunction : function() {
	},
	deleteLine : function(/* Array[][] */dataTable,/* int */index) {
		for ( var i = index - 1; i >= 0; i--) {
			for ( var j = 0; j < dataTable.length; j++) {
				dataTable[j][i + 1] = dataTable[j][i];
				dataTable[j].shift();
				dataTable[j].unshift(0);
			}
		}
	},
	/*
	 * Returns the count of cleared lines,which the lines are full fixed.
	 */
	clearLine : function(/* Array[][] */dataTable) {
		var clearCount = 0;
		for ( var i = 0; i < dataTable[0].length; i++) {
			if (TetrisUtil.sumAryX(dataTable, i) == dataTable.length) {
				clearCount++;
				TetrisUtil.deleteLine(dataTable, i);
			}
		}
		return clearCount;
	},
	/*
	 * Merge a position array(bar array)into a base table. using the (given
	 * function/default function) to process
	 * baseTable[posAry[i][0]][posAry[i][0]] the given function would get two
	 * arguments,first is the effecting cell of basetable,second is posAry[i].
	 * FIX ME: I didn't explained it clearly.
	 */
	mergePos : function(/* Array[][] */baseTable,/* Array[4][2] */posAry,/* Optional,Function */operation) {
		operation = operation || function() {
			return 2;
		}
		for ( var i = 0; i < posAry.length; i++) {
			if (typeof baseTable[posAry[i][0]][posAry[i][1]] == "undefined") {
				throw "error";
			}
			baseTable[posAry[i][0]][posAry[i][1]] = operation(baseTable[posAry[i][0]][posAry[i][1]], posAry[i]);
		}
		return baseTable;
	}
}
/*
 * A timer class which manages all timing events.
 */
var Timer = TetrisUtil.createClass();
/*
 * Extends the Timer's static members.
 */
TetrisUtil.mix(Timer, {
	/*
	 * A cache of all the timers.Using timer's name to map timer instance.
	 */
	timers : {},
	/*
	 * Starts all timers in the timer cache.
	 */
	startAll : function() {
		var timers = this.timers;
		for ( var i = 0; i < timers.length; i++) {
			timers[i].start();
		}
	},
	/*
	 * Stops all timers in the timer cache.
	 */
	stopAll : function() {
		var timers = this.timers;
		for ( var i = 0; i < timers.length; i++) {
			timers[i].stop();
		}
	},
	/*
	 * Returns one timer using the timer name.
	 */
	get : function(/* String */name) {
		return this.timers[name];
	},
	/*
	 * Removes and returns a timer with the certain name.
	 */
	remove : function(/* String */name) {
		var timers = TetrisUtil.toArray(this.timers);
		var ret;
		var timersnew = [];
		while (timers.length) {
			var tmp = timers.shift();
			if (tmp.name == name) {
				ret = tmp;
			} else {
				timersnew.push(tmp);
			}
		}
		return ret;
	},
	/*
	 * Returns an array of all timers.
	 */
	getAll : function() {
		return TetrisUtil.toArray(this.timers);
	}
});
/*
 * Mixin the members of all the timer instances.
 */
TetrisUtil.mix(Timer.prototype, {
	/*
	 * A switch of timer.
	 */
	started :false,
	/*
	 * invertal of the timer.
	 */
	invertal :1000,
	/*
	 * Timer name.
	 */
	name :"",
	/*
	 * Default method for timer to invok.
	 */
	method : function() {
	},
	/*
	 * Constructor,to initialize a timer.If the name is used ,it will throw an
	 * exception.
	 */
	initialize : function(/* String */name,/* int */invertal,/* Function */method) {
		if (this.constructor.timers[name]) {
			throw "has this timer already";
		} else {
			this.constructor.timers[name] = this;
		}
		this.name = name;
		if (typeof invertal != "undefined") {
			this.invertal = invertal;
		}
		;
		if (method) {
			this.method = method;
		}
		;
	},
	/*
	 * The core of Timer,Cycle invok this method in order to invok this timer's
	 * method.
	 */
	doTimer : function() {
		if (!this.started) {
			return;
		}
		setTimeout(TetrisUtil.bind(arguments.callee, this), this.invertal);
		this.method();
	},
	/*
	 * To start this timer.
	 */
	start : function() {
		if (!this.started) {
			this.started = true;
			this.doTimer();
		}
	},
	/*
	 * To stop this timer,the current running time is not effected.
	 */
	stop : function() {
		this.started = false;
	},
	showBar : function(bar,render) {
		render.appendChild( this.createPad(10,10).table);
		
	}
});
/*
 * Main Class of the tetris Game.
 */
var Tetris = TetrisUtil.createClass();
/*
 * Static consts of the game,now only conatins the type of the controller.
 */
Tetris.CONSTS = {
	KEYBOARD :"keyboard",
	AI :"ai"
}
/*
 * Add all base behavior of tetris game.
 */
TetrisUtil.mix(Tetris.prototype, {
	/*
	 * Specify the current status of the game.
	 */
	status : {},
	/*
	 * All bar data in this 2d array.each is an array of bar.
	 */
	barData : [ [ [ 4, 2 ], [ 4, 3 ], [ 5, 3 ], [ 6, 3 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 4, 3 ], [ 4, 4 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 6, 2 ], [ 6, 3 ] ], [ [ 5, 2 ], [ 5, 3 ], [ 5, 4 ], [ 4, 4 ] ], [ [ 6, 2 ], [ 6, 3 ], [ 4, 3 ], [ 5, 3 ] ], [ [ 4, 2 ], [ 4, 3 ], [ 4, 4 ], [ 5, 4 ] ], [ [ 4, 2 ], [ 4, 3 ], [ 5, 2 ], [ 6, 2 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 5, 3 ], [ 5, 4 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 5, 3 ], [ 6, 3 ] ], [ [ 5, 2 ], [ 5, 3 ], [ 4, 3 ], [ 4, 4 ] ], [ [ 4, 3 ], [ 5, 3 ], [ 5, 2 ], [ 6, 2 ] ], [ [ 4, 2 ], [ 4, 3 ], [ 5, 3 ], [ 5, 4 ] ],
			[ [ 4, 2 ], [ 5, 2 ], [ 6, 2 ], [ 5, 3 ] ], [ [ 4, 2 ], [ 4, 3 ], [ 4, 4 ], [ 5, 3 ] ], [ [ 5, 2 ], [ 5, 3 ], [ 4, 3 ], [ 6, 3 ] ], [ [ 5, 2 ], [ 5, 3 ], [ 5, 4 ], [ 4, 3 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 4, 3 ], [ 5, 3 ] ], [ [ 4, 2 ], [ 5, 2 ], [ 4, 3 ], [ 5, 3 ] ], [ [ 3, 2 ], [ 4, 2 ], [ 5, 2 ], [ 6, 2 ] ], [ [ 5, 2 ], [ 5, 3 ], [ 5, 4 ], [ 5, 5 ] ] ],
	/*
	 * Method of initialize,specify the game's name,render, and the col/row
	 * counts.
	 */
	initialize : function(name, render, width, height) {
		this.render = render = document.getElementById(render);
		var padInfo = this.createPad(width, height);
		this.name = name;
		this.table = padInfo.table;
		this.tableMap = padInfo.tableMap;
		this.dataTable = padInfo.dataTable;
		this.rect = {
			width :width,
			height :height
		}
		render.appendChild(this.table);
		this.status = {};
		pageContext.tetris[name] = this;
	},
	/*
	 * replace the current game with an stopped empty game.
	 */
	clear : function() {
		var padInfo = this.createPad(this.rect.width, this.rect.height);
		this.table = padInfo.table;
		this.tableMap = padInfo.tableMap;
		this.dataTable = padInfo.dataTable;
		this.render.innerHTML = "";
		this.render.appendChild(this.table);
		this.status = {};
		this.refresh();
	},
	/*
	 * Create the game pad to display,and the data model's in memory;
	 */
	createPad : function(width, height) {
		var table = document.createElement('table');
		table.className = "pad";
		var tbody = document.createElement('tbody');
		table.appendChild(tbody);
		var tableMap = [];
		var dataTable = [];
		for ( var i = 0; i < height; i++) {
			var tr = document.createElement("tr");
			if (i < 2) {
				tr.style.display = "none";
			}
			tbody.appendChild(tr);
			for ( var j = 0; j < width; j++) {
				var td = document.createElement("td");
				td.className = "blank";
				tr.appendChild(td);
				tableMap[j] = tableMap[j] || [];
				dataTable[j] = dataTable[j] || [];
				tableMap[j][i] = td;
				dataTable[j][i] = 0;
			}
		}
		return {
			table :table,
			tableMap :tableMap,
			dataTable :dataTable
		};
	},
	/*
	 * Get a new bar.If the bar No. is not specified ,use an random bar.
	 */
	newBar : function(barSN) {
		barSN = (typeof barSN == "undefined") ? Math.floor(Math.random() * this.barData.length) : barSN;
		var ret ;
		if(!this.status.nextBar) {
			this.status.nextBar = this.barData[Math.floor(Math.random() * this.barData.length)];
		}
		ret = this.status.bar = this.status.nextBar;
		this.status.nextBar = this.barData[barSN];
		return  ret;
	},
	/*
	 * Check if the specified step is available .Param absPos is a absolute
	 * position array of a bar;
	 */
	validateStep : function(absPos) {
		var copyOfDataTable = TetrisUtil.cloneAry(this.dataTable);

		try {
			TetrisUtil.mergePos(copyOfDataTable, absPos, function() {
				return arguments[0] + 2;
			});
			var toCheckAry = TetrisUtil.cloneSimpleAry(copyOfDataTable);
			for ( var i = 0; i < toCheckAry.length; i++) {
				if (toCheckAry[i] > 2) {
					return false;
				}
			}
			return true;
		} catch (e) {
			return false;
		}
	},
	/*
	 * Refresh the table to display.
	 */
	refresh : function() {
		for ( var i = 0; i < this.dataTable.length; i++) {
			for ( var j = 2; j < this.dataTable[i].length; j++) {
				switch (this.dataTable[i][j]) {
				case 0:
					this.tableMap[i][j].className = "blank";
					break;
				case 1:
					this.tableMap[i][j].className = "fill";
					break;
				case 2:
					this.tableMap[i][j].className = "active";
					break;
				default:
					this.tableMap[i][j].className = "error";
					break;
				}
			}
		}
	},
	/*
	 * Join the offset to the given position(bar),and returns a new one ,without
	 * modifying the given param.
	 */
	joinOffsetToPos : function(posAry, offset) {
		var ret = [];
		for ( var i = 0; i < posAry.length; i++) {
			ret[i] = TetrisUtil.cloneSimpleAry(posAry[i]);
			ret[i][0] += offset[0];
			ret[i][1] += offset[1];
		}
		return ret;
	},
	/*
	 * Make a bar static,mostly used when a bar shouldn't move.
	 */
	fixBar : function(absPos) {
		TetrisUtil.mergePos(this.dataTable, absPos, function() {
			return 1;
		});
	},
	/*
	 * Set a absolute position of the tetris dataTable active(plus 2).
	 */
	setActive : function(absPos) {
		TetrisUtil.mergePos(this.dataTable, absPos, function() {
			return 2;
		});
	},
	/*
	 * Clears the active pos in the tetris dataTable.
	 */
	clearActive : function() {
		for ( var i = 0; i < this.dataTable.length; i++) {
			for ( var j = 0; j < this.dataTable[i].length; j++) {
				if (this.dataTable[i][j] == 2) {
					this.dataTable[i][j] = 0;
				}
			}
		}
	},
	/*
	 * Roll's the given bar into a new bar array,then return the new array;
	 */
	rollBar : function(bar) {
		var ret = [];
		var centerX = Math.round((bar[0][0] + bar[1][0] + bar[2][0] + bar[3][0]) / 4);
		var centerY = Math.round((bar[0][1] + bar[1][1] + bar[2][1] + bar[3][1]) / 4);
		for ( var i = 0; i < 4; i++) {
			ret[i] = [];
			ret[i][0] = centerX - bar[i][1] + centerY;
			ret[i][1] = bar[i][0] + centerY - centerX;
		}
		return ret;
	},
	/*
	 * Invoks the interface of the ControllFactory,and give the current tetirs
	 * instance to the controller.
	 */
	buildController : function(controllerFactory) {
		return controllerFactory.getNewController(this);
	},
	/*
	 * Returns the max height the given bar could drop.
	 */
	getDropHeight : function(absBar) {
		var dropHeight = this.rect.height;
		for ( var i = 0; i < absBar.length; i++) {
			var col = this.dataTable[absBar[i][0]];
			var colDropHeight = 0
			for ( var j = absBar[i][1] + 1; j < col.length; j++) {
				if (col[j] == 0) {
					colDropHeight++;
				} else
					break;
			}
			if (colDropHeight < dropHeight) {
				dropHeight = colDropHeight;
			}
		}
		return dropHeight;
	}
});
/*
 * Declare the basic behavior of the controllers(abstract class).
 */
var BasicControllerBehavior = {
	/*
	 * The controller status.
	 */
	started :false,
	/*
	 * Timer instance of this controller.
	 */
	timer :null,
	/*
	 * The speed(inveretal) of the controller for down bar.Default is 1000.
	 */
	speed :1000,
	/*
	 * Start the controller,as well as the timer in it;
	 */
	start : function() {
		if (this.started) {
			return;
		}
		this.started = true;
		this.timer = this.timer || new Timer(this.tetris.name, this.speed, TetrisUtil.bind(this.control, this));
		this.timer.start();
		this.startNewBar();
	},
	/*
	 * Stop the controller,as well as the timer in it;
	 */
	stop : function() {
		this.started = false;
		Timer.get(this.tetris.name).stop();
	},
	/*
	 * Trigger the gameover of the tetris.
	 */
	gameOver : function() {
		alert(this.tetris.name + " Game Over!");
		this.stop();
	},
	/*
	 * Stop the game and get a new stopped game.
	 */
	clear : function() {
		this.stop();
		this.tetris.clear();
	},
	/*
	 * Set the speed(invertal) of the game.
	 */
	setSpeed : function(speed) {
		this.speed = speed;
	},
	/*
	 * Trigger the bar go left.If cannot move ,returns false.
	 */
	left : function() {
		var ret = false;
		if (!this.started) {
			return false;
		}
		var _t = this.tetris;
		_t.clearActive();
		if (!_t.status.bar) {
			_t.newBar();
		}
		if (!_t.status.offset) {
			_t.status.offset = [ 0, 0 ];
		}
		var tmpOffset = TetrisUtil.cloneSimpleAry(_t.status.offset);
		tmpOffset[0]--;
		var absPos = _t.joinOffsetToPos(_t.status.bar, tmpOffset);
		if (_t.validateStep(absPos)) {
			_t.status.offset[0]--;
			ret = true;
		}
		_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
		_t.refresh();
		return ret;
	},
	/*
	 * Trigger the bar go right.If cannot move ,returns false.
	 */
	right : function() {
		var ret = false;
		if (!this.started) {
			return false;
		}
		var _t = this.tetris;
		_t.clearActive();
		if (!_t.status.bar) {
			_t.newBar();
		}
		if (!_t.status.offset) {
			_t.status.offset = [ 0, 0 ];
		}
		var tmpOffset = TetrisUtil.cloneSimpleAry(_t.status.offset);
		tmpOffset[0]++;
		var absPos = _t.joinOffsetToPos(_t.status.bar, tmpOffset);
		if (_t.validateStep(absPos)) {
			_t.status.offset[0]++;
			ret = true;
		}
		_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
		_t.refresh();
		return ret;

	},
	/*
	 * Trigger the bar go down.If cannot move ,make it static.
	 */
	down : function() {
		if (!this.started) {
			return false;
		}
		var ret;
		var _t = this.tetris;
		_t.clearActive();
		if (!_t.status.bar) {
			_t.newBar();
		}
		if (!_t.status.offset) {
			_t.status.offset = [ 0, 0 ];
		}
		var tmpOffset = TetrisUtil.cloneSimpleAry(_t.status.offset);
		tmpOffset[1]++;
		var absPos = _t.joinOffsetToPos(_t.status.bar, tmpOffset);
		if (_t.validateStep(absPos)) {
			_t.status.offset[1]++;
			ret = true;
		} else {
			var _fixPos = _t.joinOffsetToPos(_t.status.bar, _t.status.offset);
			_t.fixBar(_fixPos);
			_t.clearActive();
			TetrisUtil.clearLine(_t.dataTable);
			_t.status.offset = [ 0, 0 ];
			_t.newBar();
			this.startNewBar();
			for ( var i = 0; i < _fixPos.length; i++) {
				if (_fixPos[i][1] <= 2) {
					this.gameOver();
					return false;
				}
			}
			ret = false;
		}
		_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
		_t.refresh();
		return ret;
	},
	/*
	 * Roll the current bar..If cannot roll ,returns false.
	 */
	rollBar : function() {
		if (!this.started) {
			return false;
		}
		var _t = this.tetris;
		_t.clearActive();
		if (!_t.status.bar) {
			_t.newBar();
		}
		if (!_t.status.offset) {
			_t.status.offset = [ 0, 0 ];
		}
		var tmpBar = _t.rollBar(_t.status.bar);
		var absPos = _t.joinOffsetToPos(tmpBar, _t.status.offset);
		if (_t.validateStep(absPos)) {
			_t.status.bar = tmpBar;
			_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
			_t.refresh();
			return true;
		} else {
			_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
			return false;
		}
	},
	/*
	 * Drop the bar on to the bottom and make it static.
	 */
	drop : function() {
		if (!this.started) {
			return false;
		}
		var ret;
		var _t = this.tetris;
		_t.clearActive();
		if (!_t.status.bar) {
			_t.newBar();
		}
		if (!_t.status.offset) {
			_t.status.offset = [ 0, 0 ];
		}
		var absPos = _t.joinOffsetToPos(_t.status.bar, _t.status.offset);
		_t.clearActive();
		var dropHeight = _t.getDropHeight(absPos);
		_t.status.offset[1] += dropHeight;
		var _fixPos = _t.joinOffsetToPos(_t.status.bar, _t.status.offset);
		_t.fixBar(_fixPos);
		_t.clearActive();
		TetrisUtil.clearLine(_t.dataTable);
		_t.status.offset = [ 0, 0 ];
		_t.newBar();
		this.startNewBar();
		for ( var i = 0; i < _fixPos.length; i++) {
			if (_fixPos[i][1] == 0) {
				this.gameOver();
				return false;
			}
		}
		_t.setActive(_t.joinOffsetToPos(_t.status.bar, _t.status.offset));
		_t.refresh();
		ret = false;
		return ret;
	},
	/*
	 * The function of downing bar.
	 */
	control : function() {
		if (this.started) {
			this.down();
		}
	},
	/*
	 * Triggered by starting a new bar.Default is an empty function.
	 */
	startNewBar :TetrisUtil.emptyFunction
}
/*
 * KeyBoardController factory. For a tetris game to get a keyboard controller.
 */
var KeyBoardControllerFactory = {
	/*
	 * Returns a new controller,with the reference of the tetris.
	 */
	getNewController : function(tetris) {
		return new KeyBoardController(tetris);
	}
}
/*
 * AIControllerFactory factory. For a tetris game to get a AI controller.
 */
var AIControllerFactory = {
	getNewController : function(tetris) {
		return new AIController(tetris);
	}
}
/*
 * AI controller class.
 */
var AIController = TetrisUtil.createClass();
/*
 * Extends the controllers' base behavior into AI controller;
 */
TetrisUtil.mix(AIController.prototype, BasicControllerBehavior);
/*
 * Add the implement of the AI controller.
 */
TetrisUtil.mix(AIController.prototype, {
	/*
	 * Init of the controller.Creates the controller and cache in pageContext.
	 */
	initialize : function(tetris) {
		this.tetris = tetris;
		this.type = Tetris.CONSTS.AI;
		pageContext.controller[this.tetris.name] = this;
	},
	/*
	 * Calculate the best position and move.
	 */
	aiMove : function() {
		var best = this.calcBest();
		this.move(best.x, best.roll);
	},
	/*
	 * Calculate the best position and roll.Iterate every possible situation.
	 */
	calcBest : function() {
		var _t = this.tetris;
		var bar = TetrisUtil.cloneAry(_t.status.bar);
		var status = {
			x :0,
			roll :0,
			value :0
		};
		for ( var roll = 0; roll < 4; roll++) {
			var offset = [ 0, 0 ];
			var absPos = _t.joinOffsetToPos(bar, offset);
			while (_t.validateStep(absPos)) {
				var result = this.calc(absPos);
				if (result > status.value) {
					status.x = offset[0];
					status.roll = roll;
					status.value = result;
				}
				offset[0]--;
				absPos = _t.joinOffsetToPos(bar, offset);
			}
			offset = [ 1, 0 ];
			absBar = _t.joinOffsetToPos(bar, offset);
			while (_t.validateStep(absBar)) {
				var result = this.calc(absBar);
				if (result > status.value) {
					status.x = offset[0];
					status.roll = roll;
					status.value = result;
				}
				offset[0]++;
				absBar = _t.joinOffsetToPos(bar, offset);
			}
			bar = _t.rollBar(bar);
		}
		return status;
	},
	/*
	 * Calculate the value of an absolute position(didn't drop).The lager,the
	 * better.
	 */
	calc : function(absBar) {
		var _t = this.tetris;
		var offset = [ 0, _t.getDropHeight(absBar) ];
		absBar = _t.joinOffsetToPos(absBar, offset);
		var copyTable = TetrisUtil.cloneAry(_t.dataTable);
		TetrisUtil.mergePos(copyTable, absBar, function() {
			return 1;
		});
		return this.calcValue(copyTable, absBar);
	},
	/*
	 * Calculate the value of an absolute position(dropped).The lager,the
	 * better.
	 */
	calcValue : function(fixedTable, absBar) {
		var value = 1;
		var empty = 1;
		var shape = 0;
		var floor = 1;
		var beside = 1;

		TetrisUtil.mergePos(fixedTable, absBar, function() {
			return arguments[0] + 2;
		});
		for ( var i = 0; i < absBar.length; i++) {
			floor += absBar[i][1];
			if (typeof fixedTable[absBar[i][0]][absBar[i][1] + 1] == "undefined") {
				shape += 2;
			} else {
				if (fixedTable[absBar[i][0]][absBar[i][1] + 1] == 1) {
					shape += 2;
				} else if (fixedTable[absBar[i][0]][absBar[i][1] + 1] == 0) {
					empty++;
				} else if (fixedTable[absBar[i][0]][absBar[i][1] + 1] == 3) {
					shape -= 0.2;
				}

				for ( var j = absBar[i][1] + 2; j < fixedTable.length; j++) {
					if (fixedTable[absBar[i][0]][absBar[i][j]] == 0) {
						empty += 1;
					}
				}
			}
			if ((typeof fixedTable[absBar[i][0] + 1] == "undefined") || (typeof fixedTable[absBar[i][0] - 1] == "undefined")) {
				beside++;
			} else if (fixedTable[absBar[i][0] + 1][absBar[i][1]] == 1) {
				beside++;
			} else if (fixedTable[absBar[i][0] - 1][absBar[i][1]] == 1) {
				beside++;
			}
		}
		var rowsFilld = 0;
		var count = 0;
		for ( var j = 0; j < this.tetris.rect.height; j++) {
			var sum = TetrisUtil.sumAryX(fixedTable, j);
			if (sum > 0) {
				count++;
			}
			rowsFilld += sum;
		}
		rowsFilld = rowsFilld / count;
		var lines = TetrisUtil.clearLine(fixedTable);
		this.tetris.refresh();
		var ret = this.AIFunction(floor, lines, shape, beside, rowsFilld, empty);
		return ret;
	},
	/*
	 * Internal function.while a new bar started ,it is invoked.
	 */
	startNewBar : function() {
		this.aiMove();
	},
	/*
	 * Give x offset and times of rolling,to move to the specified position.
	 */
	move : function(x, roll) {
		var _s = this.tetris.status;
		for ( var i = 0; i < roll; i++) {
			if (!this.rollBar()) {
				return;
			}
		}
		if (x > _s.offset[0]) {
			while (x > _s.offset[0]) {
				if (!this.right()) {
					return;
				}
			}
		} else if (x < _s.offset[0]) {
			while (x < _s.offset[0]) {
				if (!this.left()) {
					return;
				}
			}
		}
	},
	/*
	 * The function to calculate the position weight.
	 */
	AIFunction : function(floor, lines, shape, beside, rowsFilld, empty) {
		return Math.pow(lines * lines + 1, 3) * Math.pow(shape, 3) * Math.pow(beside + 2, 5) * Math.pow(rowsFilld, 2) * Math.pow(floor, 5) / (Math.pow(empty, 4));
	}
});
/*
 * Keyboard controller class.
 */
var KeyBoardController = TetrisUtil.createClass();
/*
 * Extends the controllers' base behavior into Keyboard controller;
 */
TetrisUtil.mix(KeyBoardController.prototype, BasicControllerBehavior);
/*
 * Implements the Keyboard controller.
 */
TetrisUtil.mix(KeyBoardController.prototype, {
	/*
	 * Init of the controller.Creates the controller and cache in pageContext
	 * whith a default key map.
	 */
	initialize : function(tetris) {
		this.tetris = tetris;
		this.type = Tetris.CONSTS.KEYBOARD;
		pageContext.controller[this.tetris.name] = this;
		this.setKeyMap( {
			UP :38,
			DOWN :40,
			LEFT :37,
			RIGHT :39,
			DROP :32
		});
	},
	/*
	 * Replace the old key map with a new one.
	 */
	setKeyMap : function(keyMap) {
		pageContext.keyMap[this.tetris.name] = keyMap;
	},
	/*
	 * Dispatch the event to the specified method to control the tetris.
	 */
	move : function(keyCode) {
		var name = this.tetris.name;
		switch (keyCode) {
		case pageContext.keyMap[name].UP:
			this.rollBar();
			break;
		case pageContext.keyMap[name].DOWN:
			this.down();
			break;
		case pageContext.keyMap[name].LEFT:
			this.left();
			break;
		case pageContext.keyMap[name].RIGHT:
			this.right();
			break;
		case pageContext.keyMap[name].DROP:
			this.drop();
			break;
		}
	}
});
/*
 * The keyboard event dispatcher .
 */
var EventDispatcher = function() {
	for ( var name in pageContext.controller) {
		if (pageContext.controller[name].type == Tetris.CONSTS.KEYBOARD) {
			pageContext.controller[name].move(event.keyCode);
		}
	}
};
/*
 * Context of the page.
 */
var pageContext = {
	tetris : {},
	controller : {},
	keyMap : {}
};
/*
 * Load method on page complete.AI
 */
function load() {
	var tetris = new Tetris("myTetris1", "render1", 10, 19);
	window.ctrl1 = tetris.buildController(AIControllerFactory);
	window.ctrl1.setSpeed(25);
	ctrl1.start();
}
//Keyboard
//function load() {
//	var tetris = new Tetris("myTetris1", "render1", 10, 19);
//	window.ctrl1 = tetris.buildController(KeyBoardControllerFactory);
//	ctrl1.setKeyMap({
//	UP:87,
//	DOWN:83,
//	LEFT:65,
//	RIGHT:68,
//	DROP:18
//	});
//	ctrl1.start();
//}

洋洋洒洒1000行。。自己留个底吧
分享到:
评论

相关推荐

    VC版人工智能俄罗斯方块

    《VC版人工智能俄罗斯方块》是一款基于Visual C++编写的具有人工智能元素的俄罗斯方块游戏。这个项目不仅提供了传统俄罗斯方块的基本玩法,更引入了AI算法,使得游戏更具挑战性和趣味性。以下是对该项目中涉及的主要...

    基于java的俄罗斯方块,带人工智能(AI)

    《基于Java的俄罗斯方块与人工智能(AI)详解》 在计算机编程领域,游戏开发是一项极具挑战性的任务,尤其当涉及到人工智能(AI)时。本文将深入探讨一款基于Java实现的俄罗斯方块游戏,该游戏中融入了AI元素,使得...

    基于C++的AI俄罗斯方块设计

    在本项目中,“基于C++的AI俄罗斯方块设计”是一项将经典的俄罗斯方块游戏与人工智能(AI)技术相结合的编程挑战。这个项目的核心目标是创建一个具备智能决策能力的俄罗斯方块游戏,使得计算机玩家能够自动进行有效...

    俄罗斯方块AI 策略

    俄罗斯方块是一款经典的电子游戏,其简单易懂的规则和高度的可玩性使其成为全球玩家喜爱的休闲游戏。在这款游戏中,AI策略的应用旨在实现自动控制下落的方块,以达到消除行、获得高分的目标。本文将详细介绍一种基于...

    有自动游戏功能的俄罗斯方块

    《有自动游戏功能的俄罗斯方块》是一款基于C++编程语言开发的游戏,融合了经典游戏俄罗斯方块的玩法与人工智能技术。在这个项目中,开发者使用了codeblocks 8.02作为集成开发环境,wxwidgets 2.8.10作为图形用户界面...

    基于C 与WinAPI的AI俄罗斯方块.zip

    本文将深入探讨一个开源项目——"基于C语言与WinAPI的AI俄罗斯方块",通过这个项目,我们可以了解如何利用C语言和Windows API来开发游戏,并实现人工智能算法。 首先,C语言是一种底层、通用的编程语言,以其高效性...

    AI俄罗斯方块下落策略

    本文探讨了一种将人工智能(AI)与正则表达式(RegularExpression)结合应用于经典游戏俄罗斯方块的新策略。传统的俄罗斯方块游戏采用的是较为简单的AI算法,而本文的研究团队试图通过引入更高级的AI技术和正则表达式的...

    俄罗斯方块游戏源代码

    俄罗斯方块,这款起源于苏联的经典电子游戏,以其简单易上手、趣味无穷的特点,历经数十年仍然深受玩家喜爱。本篇将深入探讨其游戏机制、实现原理以及VC++环境下的源码分析。 一、游戏机制 俄罗斯方块的基本元素是...

    俄罗斯方块源码

    《Linux环境下C语言实现的俄罗斯方块源码解析》 在计算机编程的世界中,经典游戏“俄罗斯方块”一直是学习新技能和理解编程原理的绝佳案例。本项目以C语言在Linux操作系统下实现了这一著名游戏,涉及的知识点包括...

    用C编的俄罗斯方块开发代码.rar_人工智能_俄罗斯方块_俄罗斯方块 c_图像处理_流媒体

    人工智能在俄罗斯方块中的应用可能体现在自动落块功能或者AI对战模式。在自动落块功能中,可以使用简单的策略,如尽快直线下降,或者更复杂的方法,如最小化未来潜在空缺。AI对战则可能涉及更复杂的算法,如模拟对手...

    智能俄罗斯方块

    《智能俄罗斯方块》是一款融合了经典游戏与人工智能技术的创新版俄罗斯方块。这款游戏中,玩家不仅可以体验传统的自我挑战模式,还能与智能计算机进行激烈的对战。游戏提供了两个不同的界面,分别是玩家控制和电脑...

    eluosi.rar_tetris_人工智能_俄罗斯方块

    在这款融合了人工智能的俄罗斯方块中,AI算法可能采用了机器学习的方法。机器学习允许程序通过大量的数据训练,自我优化并改进策略。例如,它可能通过深度强化学习,不断试错,学习如何更有效地消除行,甚至预测下落...

    pygame做的俄罗斯方块游戏

    5. **AI对战**:在人机对战模式下,AI(人工智能)需要根据游戏规则选择最佳的落地方位。这可能涉及到简单的策略,如最小化行消除的可能性,或者更复杂的算法如Minimax或Alpha-Beta剪枝。 6. **多语言支持**:游戏...

    Java版俄罗斯方块小游戏源码

    【Java版俄罗斯方块】 增加保存配置信息到文件的功能,声音设置、显示设置、关卡选择等配置信息在修改后将会保存在jar包同级目录下(以jar相同的文件名+.cfg后缀保存) 2010-10-05 【Java版俄罗斯方块】 这个程序...

    俄罗斯方块J2ME下载

    在游戏界,俄罗斯方块不仅是一款休闲益智游戏,也是研究游戏理论和人工智能的重要参考,因为它涉及空间感知、快速决策和模式识别等多方面能力的锻炼。 【压缩包子文件的文件名称列表】:综合考试 在提供的信息中,...

    俄罗斯方块

    总的来说,《俄罗斯方块》虽简单,但其背后的编程实现涉及到许多计算机科学和软件工程的基础知识,包括数据结构、算法、图形处理、事件驱动编程以及用户界面设计等。通过研究这样的源代码,开发者和学习者都能从中...

    人工智能大作业,一个俄罗斯方块,采用了pierre dellacherie算法实现电脑智能堆积俄罗斯方块

    总的来说,Pierre Dellacherie算法在俄罗斯方块中的应用是一个很好的示例,展示了人工智能如何在简单游戏中创造复杂而有趣的策略。这不仅是对AI技术的探索,也是对游戏设计的一次革新,对于学习和研究AI的初学者来说...

    俄罗斯方块简单实现带键盘控制

    【俄罗斯方块简单实现带键盘控制】是一个编程项目,它基于经典的电子游戏“俄罗斯方块”,并添加了键盘输入功能,使玩家能够通过键盘来控制方块的移动、旋转和消除。这个项目对于初学者来说是很好的实践,因为它涵盖...

    基于egret开发的俄罗斯方块(拓展篇)

    《基于Egret开发的俄罗斯方块:拓展与深度解析》 在当今的H5游戏领域,Egret引擎以其轻量级、高效能的特点深受开发者喜爱。本项目以“基于Egret开发的俄罗斯方块(拓展篇)”为主题,不仅实现了经典游戏俄罗斯方块...

    基于穷举搜索的AI自动实现俄罗斯方块游戏

    实现了一个简单的俄罗斯方块AI,用于预测并选择最优的形状放置位置,以尽可能消除更多的方块行。完整的代码下:(包含注释) tetris_game.py是主函数,主要为应用界面的主函数。 tetris_model.py是游戏的数据模型。 ...

Global site tag (gtag.js) - Google Analytics