Tron
forked from test (diff: 597)
ActionScript3 source code
/**
* Copyright h_kamizono ( http://wonderfl.net/user/h_kamizono )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/p0rD
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.display.Graphics;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.trace.Trace;
import flash.utils.setTimeout;
/**
*
* ゲームのAIを作成してどのAIが強いかを競う大会 Google AI Challenge)
* で使われていたゲームをActionScript3.0で作ってみました。
*
* ゲーム
* へびゲーム
* ( http://ja.wikipedia.org/wiki/%E3%83%98%E3%83%93%E3%82%B2%E3%83%BC%E3%83%A0 )
* とほぼおなじ内容です。壁、相手と自分(相手)が通った道とおなじマスに行かないように移動してください。
* プレイヤー1は赤色で、先頭が濃い赤で通ったところは薄い赤で描画されます。
* プレイヤー2は緑色で、先頭が濃い緑で通ったところは薄い緑で描画されます。
*
* 操作
* テンキーの十字で上なら↑、右なら→、下なら↓、左なら←で移動できます。
*
* AIにかんして
* AIを改造したい場合は、MyTronBotクラスのmakeMoveを変えるだけでいいです。
* AI同士を戦わせるにはPlayerクラスのところを、新たに作成したMyTronBotクラスで置き換えればいいです。
*
* @author h_kamizono
*/
[SWF(width="465",height="465",backgroundColor="#ffffff")]
public class Main extends Sprite
{
private var _map:Map = new Map();
private var _text:Text;
private var bot1p:MyTronBot;
private var bot2p:MyTronBot;
private var _player:Player;
private var _prepos1p:Node;
private var _prepos2p:Node;
private var _result:int;
// ゲームスピードの設定、小さいほどはやい
private var _timer:Timer = new Timer(90);
// nodeをremoveするための配列
private var _nodes:Array;
public function Main():void
{
_text = new Text();
_text.display(this, "");
gameInit();
gameStart();
}
private function gameInit():void
{
_map.init();
_text.setText("自分が通ったところと相手が通ったところは\n壁とおなじなのでぶつからないように避けましょう。");
// botのインスタンス作成
// bot同士戦わせるには下のコメントアウトを消して、_playerの行を消す
//bot1p = new MyTronBot();
bot2p = new MyTronBot();
// 人がプレイする時は1pで固定
_player = new Player();
stage.focus = _player;
_prepos1p = null;
_prepos2p = null;
_result = 0;
_nodes = new Array();
}
private function gameStart():void
{
// 初期画面描画
draw();
// ゲーム開始
_timer.addEventListener(TimerEvent.TIMER, gameLoop);
_timer.start();
}
private function draw():void
{
for (var i:int = 0; i < _map.height; i++)
{
for (var j:int = 0; j < _map.width; j++)
{
var node:Node = new Node(j, i);
// プレイヤー1を描画
if (_map.opX() == j && _map.opY() == i)
{
node.draw(0xcc6666);
}
// プレイヤー2を描画
else if (_map.tpX() == j && _map.tpY() == i)
{
node.draw(0x66cc66);
}
else
{
// 壁を描画
if (_map.walls[j][i])
{
node.draw(0x111111);
}
// 何もないところは真白で描画
else
{
node.draw(0xffffff);
}
}
addChild(node);
_nodes.push(node);
}
}
}
private function gameLoop(event:TimerEvent):void
{
var od:int = _player.makeMove();
// botの移動方向決定、bot同士で戦わせるには、上のプレイヤーのをコメントアウト
// 下のコメントアウトを消す
//var od:int = bot1p.makeMove(_map);
var td:int = bot2p.makeMove(_map.swapPlayers());
// 1p,2pの移動
var om:int = _map.move1p(od);
var tm:int = _map.move2p(td);
// お互いぶつかったのでドロー
if (_map.opX() == _map.tpX() && _map.opY() == _map.tpY())
{
gameOver(1);
}
// お互い壁にぶつかったのでドロー
else if (om < 0 && tm < 0)
{
gameOver(1);
}
// プレイヤー2の勝ち
else if (om < 0)
{
gameOver(2);
}
// プレイヤー1の勝ち
else if (tm < 0)
{
gameOver(3);
}
// 描画更新
update();
}
private function gameOver(i:int):void
{
_result = i;
// ゲーム終了
_timer.removeEventListener(TimerEvent.TIMER, gameLoop);
_text.setText("");
switch (_result)
{
// Draw
case 1:
_text.setText("Draw \n Enter キーで再スタートできます。");
break;
// 2p勝利
case 2:
_text.setText("2P Win \n Enter キーで再スタートできます。");
break;
// 1p勝利
case 3:
_text.setText("1P Win \n Enter キーで再スタートできます。");
break;
default:
break;
}
stage.focus = stage;
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.ENTER)
{
restart();
}
});
}
private function update():void
{
var pos1p:Node = new Node(_map.opY(), _map.opX());
pos1p.draw(0xff0000);
addChild(pos1p);
_nodes.push(pos1p);
if (_prepos1p)
{
_prepos1p.draw(0xcc6666)
addChild(_prepos1p);
}
_prepos1p = pos1p;
var pos2p:Node = new Node(_map.tpY(), _map.tpX());
pos2p.draw(0x339933);
addChild(pos2p);
_nodes.push(pos2p);
if (_prepos2p)
{
_prepos2p.draw(0x66cc66)
addChild(_prepos2p);
}
_prepos2p = pos2p;
}
private function restart():void
{
for (var i:int = 0; i < _nodes.length; i++)
{
removeChild(_nodes[i]);
_nodes[i] = null;
}
gameInit();
gameStart();
}
}
}
import flash.display.Graphics;
import flash.trace.Trace;
import flash.geom.Point;
class Map {
// マップの幅と高さ
private var _width:int = 15;
private var _height:int = 15;
// マップにある壁用の変数
private var _walls:Vector.<Vector.<Boolean>>;
// プレイヤーの位置を保存
private var _opLocation:Point;
private var _tpLocation:Point;
/*
* マップ用のデータ
* wは壁
* 1はプレイヤー1(1つだけ)
* 2はプレイヤー2(1つだけ)
*/
private var _maps:Vector.<String> =
Vector.<String>(["wwwwwwwwwwwwwww",
"w1 w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w w",
"w 2w",
"wwwwwwwwwwwwwww"]);
public function Map()
{
}
public function init():void
{
_walls = new Vector.<Vector.<Boolean>>();
for (var i:int = 0; i < height; i++)
{
var tmp:Vector.<Boolean> = new Vector.<Boolean>();
for (var j:int = 0; j < width; j++)
{
tmp.push(false);
}
_walls.push(tmp);
}
readMapData();
}
public function get width():int
{
return _width;
}
public function get height():int
{
return _height;
}
public function get walls():Vector.<Vector.<Boolean>>
{
return _walls;
}
// i,jにあるマスが壁かどうか
public function isWall(i:int, j:int):Boolean
{
if (i <= 0 || j <= 0 || i >= width - 1 || j >= height - 1)
return true;
else
return _walls[i][j];
}
public function opX():int
{
return _opLocation.x;
}
public function opY():int
{
return _opLocation.y;
}
public function tpX():int
{
return _tpLocation.x;
}
public function tpY():int
{
return _tpLocation.y;
}
public function readMapData():void
{
// プレイヤー1,2は1人だけかどうかのフラグ
var flag1:Boolean = false;
var flag2:Boolean = false;
var w:int = 0;
var h:int = 0;
do
{
if (w >= width || h >= height) break;
var s:String = _maps[w].charAt(h);
switch (s)
{
case "\n": continue;
case " ": // ' '
_walls[w][h] = false;
break;
case "w": // 'w'
_walls[w][h] = true;
break;
case "1": // '1'
if (flag1)
{
trace("ERROR プレイヤー1が1人でないです。");
}
_walls[w][h] = true;
_opLocation = new Point(w, h);
flag1 = true;
break;
case "2": // '2'
if (flag2)
{
trace("ERROR プレイヤー2が1人でないです。");
}
_walls[w][h] = true;
_tpLocation = new Point(w, h);
flag2 = true;
break;
default:
trace(s, " そんな文字はいらないです。");
break;
}
w++;
if (w >= width)
{
h++;
w = 0;
}
} while (true);
}
public function move1p(i:int):int
{
var x:int = _opLocation.x;
var y:int = _opLocation.y;
_walls[x][y] = true;
switch (i)
{
case 1: // 左に
_opLocation = new Point(x, y - 1);
break;
case 2: // 下に
_opLocation = new Point(x + 1, y);
break;
case 3: // 右に
_opLocation = new Point(x, y + 1);
break;
case 4: // 上に
_opLocation = new Point(x - 1, y);
break;
default:
return -1;
}
x = _opLocation.x;;
y = _opLocation.y;
return !isWall(x, y) ? 0 : -1;
}
public function move2p(i:int):int
{
var x:int = _tpLocation.x;
var y:int = _tpLocation.y;
_walls[x][y] = true;
switch (i)
{
case 1: // 左に
_tpLocation = new Point(x, y - 1);
break;
case 2: // 下に
_tpLocation = new Point(x + 1, y);
break;
case 3: // 右に
_tpLocation = new Point(x, y + 1);
break;
case 4: // 上に
_tpLocation = new Point(x - 1, y);
break;
default:
return -1;
}
x = _tpLocation.x;;
y = _tpLocation.y;
return !isWall(x, y) ? 0 : -1;
}
public function swapPlayers():Map
{
var map:Map = new Map();
map._walls = this._walls;
map._width = this._width;
map._height = this._height;
map._opLocation = this._tpLocation;
map._tpLocation = this._opLocation;
return map;
}
}
// Bot用のクラス。Botを変えるときは、makeMoveの中身を変えればいい
// 今のままだと壁に当たらないように移動するだけなので弱い
class MyTronBot
{
public function makeMove(m:Map):int
{
var i:int = m.opX();
var j:int = m.opY();
if (!m.isWall(i, j - 1))
return 1;
if (!m.isWall(i, j + 1))
return 3;
if (!m.isWall(i + 1, j))
return 2;
if (!m.isWall(i - 1, j))
return 4;
else
return 1;
}
}
// プレイヤー用のクラス、switchがいいのかArrayを使った今のがいいのか
import flash.events.KeyboardEvent;
class Player extends Sprite
{
private var _keytable:Array = [];
private const VK_LEFT:int = 37;
private const VK_UP:int = 38;
private const VK_RIGHT:int = 39;
private const VK_DOWN:int = 40;
//private const VK_SPC:int = 32;
private var _direction:int = 2;
public function Player()
{
_keytable[VK_LEFT] = 1;
_keytable[VK_DOWN] = 2;
_keytable[VK_RIGHT] = 3;
_keytable[VK_UP] = 4;
this.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void
{
// キーボードの入力が_keytableにあり、逆方向の入力でないなら方向を変える
if (_keytable[e.keyCode] &&
(_keytable[e.keyCode] != _direction + 2 && _keytable[e.keyCode] != _direction - 2))
{
_direction = _keytable[e.keyCode];
}
});
}
public function set direction(d:int):void
{
_direction = d;
}
public function makeMove():int
{
return _direction;
}
}
import flash.display.Sprite;
// snamuraさんのクラス参照し、少しいじりました。
// 経路探索のためのノードクラス
internal class Node extends Sprite {
// ノードX座標
internal var fieldX:int;
// ノードY座標
internal var fieldY:int;
public function Node(fieldX:int, fieldY:int)
{
this.fieldX = fieldX;
this.fieldY = fieldY;
this.x = fieldX * 20 + 70;
this.y = fieldY * 20 + 70;
}
public function draw(background:uint):void
{
graphics.clear();
graphics.lineStyle(1);
graphics.beginFill(background);
graphics.drawRect(0,0,20,20);
}
}
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
// 文字を表示するためのクラス
class Text
{
private var _tf:TextField = null;
public function Text()
{
_tf = new TextField();
var format:TextFormat = new TextFormat();
_tf.x = 100;
format.size = 15; //
format.color = 0x000000;
format.font = "Arial";
_tf.defaultTextFormat = format;
}
public function display(sp:Sprite, text:String):void
{
_tf.text = text;
_tf.autoSize = TextFieldAutoSize.LEFT;
sp.addChild(_tf);
}
public function setText(string:String):void
{
_tf.text = string;
}
}
