/* * 新しいブロックが出てから置く場所を探しています。 * NEXTは見ていません。というよりNEXT自体を実装していません。 */ package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.utils.ByteArray; import jp.progression.commands.lists.SerialList; import jp.progression.commands.Wait; import jp.progression.commands.Func; public class Main extends Sprite { private const HEIGHT:int = 21; private const WIDTH:int = 12; private var bd:BitmapData; private var bitmap:Bitmap; private var fieldAI:Array; private var dataAI:Array; private var blockAI:Array; private var type:int; private var field:Array; private var data:Array; private var blocks:Array = [ [ [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 0, 0] ], [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0] ], [ [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0] ], [ [0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0] ], [ [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0] ], [ [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0] ], [ [0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0] ] ]; private var rb:Array = [4, 2, 2, 4, 2, 1, 4]; //private var rb:Array = [4, 4, 4, 4, 4, 4, 4]; private var block:Array; private var px:int; private var py:int; private var gameover:Boolean = false; private var count:int = 0; private var list:SerialList; public function Main() { init(); addEventListener(Event.ENTER_FRAME, draw); } private function init():void { var f:Function = function(...a):* { return 0; }; var f2:Function = function(...a):* { return new Array(WIDTH).map(f); } field = new Array(HEIGHT + 1).map(f2); data = new Array(HEIGHT + 1).map(f2); bd = new BitmapData(WIDTH, HEIGHT + 1, false, 0xFFFFFF); for (var y:int = 0; y < bd.height; y++) { for (var x:int = 0; x < bd.width; x++) { if (x == 0 || x == WIDTH - 1 || y == HEIGHT - 1) { field[y][x] = data[y][x] = Status.WALL; bd.setPixel(x, y, 0x0); } else field[y][x] = data[y][x] = Status.FIELD; } } if (bitmap) removeChild(bitmap); bitmap = new Bitmap(bd); bitmap.scaleX = bitmap.scaleY = 20; bitmap.x = (465 - bitmap.width) / 2; bitmap.y = (465 - bitmap.height) / 2; addChild(bitmap); createBlock(); solve(); } private function solve():void { var l:SerialList; var min:int = int.MAX_VALUE; var t:int = type; for (var i:int = 4; i >= -5; i--) { for (var r:int = 0; r < rb[t]; r++) { list = new SerialList(); fieldAI = clone(field); dataAI = clone(data); blockAI = clone(block); for (var r2:int = 0; r2 < r; r2++) { rotate(); add(rotate); } var j:int; if (0 <= i) { for (j = 0; j < i; j++) { left(); add(left); } } else { for (j = 0; j < i * -1; j++) { right(); add(right); } } down(); var count:int = 0; for (var y:int = 0; y < HEIGHT - 1; y++) { for (var x:int = 1; x < WIDTH - 1; x++) { if (field[y][x] == Status.FIELD) { count += y * 2; if (0 <= x - 1 && field[y][x - 1]) count += y; if (x + 1 < WIDTH && field[y][x + 1]) count += y; if (0 <= y - 1 && field[y - 1][x]) count += y; if (y + 1 < HEIGHT && field[y + 1][x]) count += y; } } } add(lock); add(createBlock); lock(); createBlock(); if (min > count) { l = list.clone() as SerialList; min = count; } field = clone(fieldAI); data = clone(dataAI); block = clone(blockAI); } } l.addCommand(new Func(solve)); l.execute(); } private function add(func:Function, args:Array = null):void { list.addCommand(new Func(func, args)); list.addCommand(new Wait(32 / 1000.0)); } private function down():void { while (!checkOverlap(px, py + 1)) { var yy:int = py; var xx:int = px; move(xx, yy + 1); add(move, [xx, yy + 1]); } } private function left():void { if (!checkOverlap(px - 1, py)) move(px - 1, py); } private function right():void { if (!checkOverlap(px + 1, py)) move(px + 1, py); } private function checkOverlap(tx:int, ty:int):Boolean { for (var y:int = 0; y < 4; y++) { for (var x:int = 0; x < 4; x++) { if (block[y][x]) { if (data[y + ty][x + tx] != 0) return true; } } } return false; } private function clone(arg:*):* { var b:ByteArray = new ByteArray(); b.writeObject(arg); b.position = 0; return b.readObject(); } private function rotate():void { var temp:Array = clone(block); for (var y:int = 0; y < 4; y++) { for (var x:int = 0; x < 4; x++) { block[y][x] = temp[3 - x][y]; } } if (checkOverlap(px, py)) { block = clone(temp); return; } for (y = 0; y < 4; y++) { for (x = 0; x < 4; x++) { field[py + y][px + x] -= temp[y][x]; field[py + y][px + x] += block[y][x]; } } } private function checkLines():void { var flag:Boolean; while (true) { for (var y:int = 0; y < 20; y++) { flag = true; for (var x:int = 1; x < 11; x++) { if (data[y][x] == 0) flag = false; } if (flag) break; } if (!flag) break; for (x = 1; x < WIDTH - 1; x++) data[y][x] = 0; for (; y > 0; y--) { for (x = 1; x < WIDTH - 1; x++) { data[y][x] = data[y - 1][x]; } } } } private function move(tx:int, ty:int):void { for (var y:int = 0; y < 4; y++) { for (var x:int = 0; x < 4; x++) { field[py + y][px + x] -= block[y][x]; } } px = tx; py = ty; for (y = 0; y < 4; y++) { for (x = 0; x < 4; x++) { field[py + y][px + x] += block[y][x]; } } } private function lock():void { for (var y:int = 0; y < HEIGHT; y++) { for (var x:int = 0; x < WIDTH; x++) { data[y][x] = field[y][x]; } } checkLines(); for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { field[y][x] = data[y][x]; } } } private function createBlock():Boolean { px = 4; py = 0; type = Math.random() * 7; block = clone(blocks[type]); for (var y:int = 0; y < 4; y++) { for (var x:int = 0; x < 4; x++) { field[y][px + x] = data[y][px + x] + block[y][x]; if (field[y][px + x] > 1) { gameover = true; return false; } } } return true; } private function draw(event:Event = null):void { bd.fillRect(bd.rect, 0xFFFFFF); for (var y:int = 0; y < HEIGHT; y++) { for (var x:int = 0; x < WIDTH; x++) { if (field[y][x] == 9) bd.setPixel(x, y, 0x0); else if (field[y][x] != 0) bd.setPixel(x, y, 0x990039); } } } } } class Status { public static const WALL:int = 9; public static const FIELD:int = 0; } テトリスAI