マモノ・スイーパーをズルしてみた
もう手でやるのめんどくさいからAIにやらせるよ!
HP:1ではじめてるから、すぐ死んだらreloadしてね!
@see http://www.hojamaka.com/game/mamono_sweeper/
// もう手でやるのめんどくさいからAIにやらせるよ!
// HP:1ではじめてるから、すぐ死んだらreloadしてね!
// @see http://www.hojamaka.com/game/mamono_sweeper/
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.*;
[SWF(frameRate=10)]
public class MSSolver extends Sprite {
private var _tf : TextField;
private var _q : Array; // ぽちらなければいけないセル
private var _mm : MS;
private var _logic : MSLogic;
public function MSSolver() {
_tf = new TextField();
_tf.width = 100;
_tf.height = 100;
addChild(_tf);
// enemy : Object = {level, hp, attack, exp, count}
_logic = new MSLogic(30, 16, [
{level:1, hp:1, attack:1, exp:1, count:33},
{level:2, hp:2, attack:2, exp:2, count:27},
{level:3, hp:3, attack:3, exp:4, count:20},
{level:4, hp:4, attack:4, exp:8, count:13},
{level:5, hp:5, attack:5, exp:16, count:6}
], 1, [10, 50, 167, 271]);
_mm = new MS(_logic);
addChild(_mm);
_mm.x = stage.stageWidth / 2;
_mm.y = stage.stageHeight / 2;
_q = [];
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e : Event) : void
{
step();
}
private function step() : void
{
var w : uint = _logic.w;
var h : uint = _logic.h;
var r : uint, c : uint;
_tf.text = "hp : " + _logic.hp + "\nlevel : " + _logic.level + "\nexp : " + _logic.exp;
// キューがあればひっくり返す
var prevlv : uint = _logic.level;
while(_q.length > 0){
var pos : Object = _q.pop();
if(_logic.hp > pos.damage && _logic.flip(pos.r, pos.c)){
break;
}
}
// しんじゃった
if(_logic.hp <= 0){
tr("\ndead end");
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// レベルアップ、またはキューがないときmarkmapをチェック
if(_q.length == 0 || prevlv < _logic.level){
for(r = 0; r < h;r++){
for(c = 0;c < w;c++){
if(_logic.flipped[r][c] == 0 && _mm.markmap[r][c] > 0){
for each(e in _logic.enemies){
if(e.level == _mm.markmap[r][c]){
// 仮想戦闘
ret = MSLogic.combat(_logic.hp, _logic.level, e.hp, e.attack);
if(ret > 0){
// 勝ったら開きに行く
_q.push({r:r, c:c, damage:_logic.hp - ret});
}
break;
}
}
}
}
}
}
if(_q.length == 0){
for(r = 0;r < h;r++){
for(c = 0;c < w;c++){
if(_logic.flipped[r][c] == 0)continue;
if((_logic.map[r][c] & 0xff) == 0)continue;
if(_mm.markmap[r][c] == 999)continue;
var cir : uint = 0;
var cirsum : uint = 0;
var unflipped : Array = [];
for(var dr : int = -1;dr <= 1;dr++){
for(var dc : int = -1;dc <= 1;dc++){
if((dr != 0 || dc != 0) && _logic.isValid(r+dr, c+dc)){
if(_logic.flipped[r+dr][c+dc] == 0){
if(_mm.markmap[r+dr][c+dc] == 0){
cir++;
unflipped.push({r:r+dr, c:c+dc, damage:0});
}else{
cirsum += _mm.markmap[r+dr][c+dc];
}
}else{
cirsum += _logic.map[r+dr][c+dc] >> 8;
}
}
}
}
if(cir >= 1){
var sub : int = (_logic.map[r][c] & 0xff) - cirsum;
if(sub > 0){
// 想定される敵を見つけて
for each(var e : Object in _logic.enemies){
if(e.level == sub){
// 仮想戦闘
var ret : int = MSLogic.combat(_logic.hp, _logic.level, e.hp, e.attack);
if(ret > 0){
// 勝ったら開きに行く
for each(var u : Object in unflipped){
u.damage = _logic.hp - ret;
_q.push(u);
}
}else{
// 負けたらマークするだけ
if(cir == 1){
u = unflipped[0];
_mm.markmap[u.r][u.c] = sub;
}
}
break;
}
}
}else{
// 敵が存在しないので無条件で開く
_q = _q.concat(unflipped);
}
}else{
_mm.markmap[r][c] = 999;
}
}
}
}
// 走査してもキューが生成されなかった場合は適当にひっくり返す
if(_q.length == 0){
var seed : Array = [];
for(r = 0;r < h;r++){
for(c = 0;c < w;c++){
if(_logic.flipped[r][c] == 0 && _mm.markmap[r][c] == 0){
seed.push({r:r, c:c});
}
}
}
if(seed.length != 0){
var candi : Object = seed[int(Math.random() * seed.length)];
candi.damage = 0;
_q.push(candi);
}else{
// 終了
tr("\nend");
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
_mm.paint();
}
private function tr(...o : Array) : void
{
_tf.appendText(o + "\n");
}
}
}
import flash.display.*;
import flash.geom.*;
import flash.text.*;
class MS extends Sprite
{
private var _logic : MSLogic;
private var _canvas : BitmapData;
private const SIZE_CELL : uint = 14;
private var _numberChips : Array;
private var _markNumberChips : Array;
private var _enemyChips : Array;
private var _unflippedChip : BitmapData;
private var _markmap : Vector.<Vector.<uint>>;
private var _h : uint;
private var _w : uint;
private const COLOR_BG : uint = 0xeeeeee;
private const COLOR_LINE : uint = 0x0;
public function get markmap() : Vector.<Vector.<uint>> { return _markmap; }
public function MS(logic : MSLogic)
{
_logic = logic;
_w = logic.w;
_h = logic.h;
_numberChips = [];
var tfmt : TextFormat = new TextFormat("arial", 10, 0x0);
var bmd : BitmapData;
var i : uint, j : uint;
for(i = 0;i <= 50;i++){
bmd = new BitmapData(SIZE_CELL, SIZE_CELL, false, COLOR_BG);
if(i >= 1){
var bmdt : BitmapData = textToBitmapData(i.toString(), tfmt);
bmd.copyPixels(bmdt, bmdt.rect, new Point((bmd.width - bmdt.width) / 2, (bmd.height - bmdt.height) / 2));
}
bmd.fillRect(new Rectangle(0, 0, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(0, 0, 1, SIZE_CELL), COLOR_LINE);
bmd.fillRect(new Rectangle(0, SIZE_CELL-1, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(SIZE_CELL-1, 0, 1, SIZE_CELL), COLOR_LINE);
_numberChips.push(bmd);
}
_markNumberChips = [];
var tfmtMark : TextFormat = new TextFormat("arial", 10, 0x00dd00);
for(i = 0;i <= 50;i++){
bmd = new BitmapData(SIZE_CELL, SIZE_CELL, false, 0x444444);
if(i >= 1){
bmdt = textToBitmapData(i.toString(), tfmtMark);
bmd.copyPixels(bmdt, bmdt.rect, new Point((bmd.width - bmdt.width) / 2, (bmd.height - bmdt.height) / 2));
}
bmd.fillRect(new Rectangle(0, 0, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(0, 0, 1, SIZE_CELL), COLOR_LINE);
bmd.fillRect(new Rectangle(0, SIZE_CELL-1, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(SIZE_CELL-1, 0, 1, SIZE_CELL), COLOR_LINE);
_markNumberChips.push(bmd);
}
_enemyChips = [null];
for each(var c : uint in [0x00ffff, 0xff0000, 0xff00ff, 0xffff00, 0x00ff00]){
bmd = new BitmapData(SIZE_CELL, SIZE_CELL, false, COLOR_BG);
bmd.fillRect(bmd.rect, c);
bmd.fillRect(new Rectangle(0, 0, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(0, 0, 1, SIZE_CELL), COLOR_LINE);
bmd.fillRect(new Rectangle(0, SIZE_CELL-1, SIZE_CELL, 1), COLOR_LINE);
bmd.fillRect(new Rectangle(SIZE_CELL-1, 0, 1, SIZE_CELL), COLOR_LINE);
_enemyChips.push(bmd);
}
_unflippedChip = new BitmapData(SIZE_CELL, SIZE_CELL, false, 0x444444);
_unflippedChip.fillRect(new Rectangle(0, 0, SIZE_CELL, 1), COLOR_LINE);
_unflippedChip.fillRect(new Rectangle(0, 0, 1, SIZE_CELL), COLOR_LINE);
_unflippedChip.fillRect(new Rectangle(0, SIZE_CELL-1, SIZE_CELL, 1), COLOR_LINE);
_unflippedChip.fillRect(new Rectangle(SIZE_CELL-1, 0, 1, SIZE_CELL), COLOR_LINE);
_markmap = new Vector.<Vector.<uint>>(_h);
for(i = 0;i < _h;i++){
_markmap[i] = new Vector.<uint>(_w);
for(j = 0;j < _w;j++){
_markmap[i][j] = 0;
}
}
_canvas = new BitmapData(SIZE_CELL * _w, SIZE_CELL * _h);
var bmp : Bitmap = new Bitmap(_canvas);
bmp.x = -SIZE_CELL * _w / 2;
bmp.y = -SIZE_CELL * _h / 2;
addChild(bmp);
paint();
}
public function paint() : void
{
_canvas.lock();
for(var i : uint = 0;i < _h;i++){
for(var j : uint = 0;j < _w;j++){
var chip : BitmapData;
if(_logic.flipped[i][j] == 0){
if(_markmap[i][j] > 0){
chip = _markNumberChips[_markmap[i][j]];
}else{
chip = _unflippedChip;
}
}else if((_logic.map[i][j] >> 8) > 0){
chip = _enemyChips[_logic.map[i][j] >> 8];
}else{
chip = _numberChips[_logic.map[i][j] & 0xf];
}
_canvas.copyPixels(chip, chip.rect, new Point(SIZE_CELL * j, SIZE_CELL * i));
}
}
_canvas.unlock();
}
private function textToBitmapData(text : String, tfmt : TextFormat = null) : BitmapData
{
var tf : TextField = new TextField();
tf.autoSize = "left";
tf.textColor = COLOR_LINE;
if(tfmt != null)tf.defaultTextFormat = tfmt;
tf.text = text;
var bmd : BitmapData = new BitmapData(tf.width, tf.height, true, COLOR_BG);
bmd.draw(tf);
return bmd;
}
}
class MSLogic
{
private var _w : uint;
private var _h : uint;
// lower 8bit : sum of neighbor levels
// upper 8bit : index of enemies
private var _map : Vector.<Vector.<uint>>;
private var _flipped : Vector.<Vector.<uint>>;
private var _enemies : Array;
private var _hp : int;
private var _exp : uint;
private var _level : uint;
private var _lvs : Array;
public function get w() : uint { return _w; }
public function get h() : uint { return _h; }
public function get map() : Vector.<Vector.<uint>> { return _map; }
public function get flipped() : Vector.<Vector.<uint>> { return _flipped; }
public function get enemies() : Array { return _enemies; }
public function get hp() : int { return _hp; }
public function get exp() : int { return _exp; }
public function get level() : uint { return _level; }
// enemy : Object = {level, hp, attack, exp, count}
public function MSLogic(w : uint, h : uint, enemies : Array, hp : int, lvs : Array)
{
_w = w;
_h = h;
_enemies = enemies;
_hp = hp;
_lvs = lvs;
_exp = 0;
_level = 1;
var i : uint, j : uint;
_map = new Vector.<Vector.<uint>>(_h);
for(i = 0;i < _h;i++){
_map[i] = new Vector.<uint>(_w);
for(j = 0;j < _w;j++)_map[i][j] = 0;
}
_flipped = new Vector.<Vector.<uint>>(_h);
for(i = 0;i < _h;i++){
_flipped[i] = new Vector.<uint>(_w);
for(j = 0;j < _w;j++)_flipped[i][j] = 0;
}
var places : Vector.<uint> = new Vector.<uint>(_w * _h);
for(i = 0;i < _w * _h;i++)places[i] = i;
for(i = 0;i < _w * _h - 1;i++){
var ind : uint = uint(Math.random() * (_w * _h - i - 1)) + i + 1;
var d : uint = places[ind];
places[ind] = places[i];
places[i] = d;
}
var p : uint = 0;
for(i = 0;i < _enemies.length;i++){
var enemy : Object = _enemies[i];
for(j = 0;j < enemy.count;j++){
var r : uint = places[p] / w;
var c : uint = places[p] % w;
_map[r][c] += (i + 1) << 8;
for(var dr : int = -1;dr <= 1;dr++){
for(var dc : int = -1;dc <= 1;dc++){
if(dr == 0 && dc == 0)continue;
if(isValid(r+dr, c+dc))_map[r+dr][c+dc] += enemy.level;
}
}
p++;
}
}
}
public function isValid(r : int, c : int) : Boolean
{
return r >= 0 && r < _h && c >= 0 && c < _w;
}
// (r,c)をひっくり返す
public function flip(r : uint, c : uint) : Boolean
{
if(_flipped[r][c] == 1)return false;
var cell : uint = _map[r][c];
var enemy : uint = _map[r][c] >> 8;
var sumlv : uint = _map[r][c] & 0xff;
if(enemy > 0){
// 敵がいる場合
_flipped[r][c] = 1;
// 戦闘
var res : int = combat(_hp, _level, _enemies[enemy-1].hp, _enemies[enemy-1].attack);
if(res <= 0){
_hp = 0;
return true;
}
_hp = res;
_exp += _enemies[enemy-1].exp;
// レベルアップ
if(_exp >= _lvs[_level - 1]){
_level++;
}
}
if(sumlv == 0){
// レベル合計が0の場合、敵のいないまわり1マスを開く
var chainFlips : Array = [[r, c]];
// マス開きの連鎖
while(chainFlips.length > 0){
var pos : Array = chainFlips.pop();
if(_flipped[pos[0]][pos[1]] == 1)continue;
if((_map[pos[0]][pos[1]] >> 8) > 0)continue;
_flipped[pos[0]][pos[1]] = 1;
if(_map[pos[0]][pos[1]] == 0){
for(var dr : int = -1;dr <= 1;dr++){
for(var dc : int = -1;dc <= 1;dc++){
if(dr == 0 && dc == 0)continue;
if(isValid(pos[0]+dr, pos[1]+dc))chainFlips.push([pos[0]+dr, pos[1]+dc]);
}
}
}
}
}else{
_flipped[r][c] = 1;
}
return true;
}
// 戦闘
public static function combat(shp : int, satk : int, ehp : int, eatk : int) : int
{
while(true){
ehp -= satk;
if(ehp <= 0)break;
shp -= eatk;
if(shp <= 0)break;
}
return (shp > 0 ? shp : 0) - (ehp > 0 ? ehp : 0);
}
}