ただのリバーシ
forked from flex ボタンイベントのテスト (diff: 769)
ActionScript3 source code
/**
* Copyright shohei909 ( http://wonderfl.net/user/shohei909 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/86fL
*/
<?xml version="1.0" encoding="utf-8"?><!-- forked from shohei909's flex ボタンイベントのテスト -->
<!--
ただのリバーシです。
とりあえず完成。
AI対戦ができます。
強さはレベル3でそこそこ。
だれかにもっと強いAIをつくてほしいけど、
こんな汚いコードじゃだれもつくってくれないだろうか?
それにしてもサムネイルがひどい・・・
errorなんて出てたらクリックする人がいなくなるよね。
なんとかならないのかな~。
-->
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
height="465" width="465"
verticalAlign="middle"
horizontalAlign="center"
applicationComplete="onLoad();"
>
<!-- エフェクトとフィルター -->
<mx:Blur id="EffectIn" duration="300"/>
<mx:Fade id="EffectOut" duration="150"/>
<mx:GlowFilter id="glow" color="0xFF6600" />
<mx:BlurFilter id="blur" blurX="2" blurY="2"/>
<mx:Script><![CDATA[
import flash.display.*;
import mx.containers.*;
import mx.core.*;
import mx.controls.Alert;
import mx.events.CloseEvent;
public var nowTurn:uint;
public var yourTurn:uint;
public var finish:Boolean;
public var timer:uint;
public var othelloSize:uint = 8;
public var rand:Number;
public var rand2:Number;
public var passNumber:uint;
public var blackNumber:uint;
public var whiteNumber:uint;
public var page:Array;
public var nowPage:int;
public var lastPage:int;
public var player:Vector.<uint>=new Vector.<uint>();
public var size:uint = 40;
public var alert:Alert = new Alert();
public var reversiMap:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(othelloSize);
public var vbox:Vector.<VBox> = new Vector.<VBox>(othelloSize);
public var cell:Vector.<Vector.<ViewStack>> = new Vector.<Vector.<ViewStack>>(othelloSize);
public var stone:Vector.<Vector.<Vector.<UIComponent>>> = new Vector.<Vector.<Vector.<UIComponent>>>(othelloSize);
public var map:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(othelloSize);
public function onLoad():void{
for(var x:uint=0;x<8;x++){
vbox[x] = new VBox();
cell[x] = new Vector.<ViewStack>(othelloSize);
stone[x] = new Vector.<Vector.<UIComponent>>(othelloSize);
reversiMap[x] = new Vector.<uint>(othelloSize);
vbox[x].setStyle("verticalGap","0");
map[x] = new Vector.<Number>(othelloSize);
field.addEventListener(MouseEvent.CLICK,click);
field.addChild(vbox[x]);
for(var y:uint=0;y<8;y++){
stone[x][y] = new Vector.<UIComponent>(3);
cell[x][y] = new ViewStack();
reversiMap[x][y] = 0;
map[x][y] = 0;
stone[x][y][0] = new Canvas();
stone[x][y][1] = new Canvas();
stone[x][y][2] = new Canvas();
stone[x][y][1].setStyle("showEffect",EffectIn);
stone[x][y][2].setStyle("showEffect",EffectIn);
stone[x][y][1].setStyle("hideEffect",EffectOut);
stone[x][y][2].setStyle("hideEffect",EffectOut);
stone[x][y][1].graphics.beginFill (0x000000, 1.0); // 面のスタイル設定
stone[x][y][1].graphics.lineStyle (2, 0x000000, 1.0); // 線のスタイル指定
stone[x][y][1].graphics.drawCircle (size/2-1, size/2-1 , size/2.2);
stone[x][y][2].graphics.beginFill (0xFFFFFF, 1.0); // 面のスタイル設定
stone[x][y][2].graphics.lineStyle (2, 0x000000, 1.0); // 線のスタイル指定
stone[x][y][2].graphics.drawCircle (size/2-1, size/2-1 , size/2.2);
cell[x][y].width=size;
cell[x][y].height=size;
cell[x][y].setStyle("borderStyle","solid");
cell[x][y].setStyle("borderColor","0x333333");
cell[x][y].addChild(stone[x][y][0]);
cell[x][y].addChild(stone[x][y][1]);
cell[x][y].addChild(stone[x][y][2]);
vbox[x].addChild(cell[x][y]);
}
}
Alert.cancelLabel="キャンセル";
Alert.buttonWidth=80;
alert = Alert.show("", "リバーシ", (Alert.OK), this, alertListener);
alert.addChildAt(config,0);
alert.width=300;
alert.height=250;
}
private function alertListener(e:CloseEvent):void {
if(e.detail == Alert.OK){
nowTurn = 1;
passNumber=0;
finish = false;
page = new Array();
nowPage = 0;
lastPage = 0;
yourTurn = selectTurn.selectedValue.valueOf();
player[0]=null; player[1]=0; player[2]=0;
player[yourTurn]=0;
player[3-yourTurn] = player2.selectedValue.valueOf();
removeEventListener(Event.ENTER_FRAME,cp);
if(player[3-yourTurn] > 0){
addEventListener(Event.ENTER_FRAME,cp);
}
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
cell[x][y].selectedIndex=0;
reversiMap[x][y] = 0;
}
}
undoButton.enabled=false;
redoButton.enabled=false;
cell[3][3].selectedIndex=2;
cell[4][3].selectedIndex=1;
cell[3][4].selectedIndex=1;
cell[4][4].selectedIndex=2;
reversiMap[3][3] = 2;
reversiMap[4][3] = 1;
reversiMap[3][4] = 1;
reversiMap[4][4] = 2;
passButton.enabled = true;
rand = Math.random();
output();
}
}
private function newGame():void{
alert = Alert.show("", "リバーシ", (Alert.OK | Alert.CANCEL), this, alertListener);
alert.addChildAt(config,0);
alert.width=300;
alert.height=250;
}
private function addNewPage():void{
page[nowPage] = new Array();
for(var x:uint=0;x<8;x++){
page[nowPage][x] = new Array();
for(var y:uint=0;y<8;y++){
page[nowPage][x][y] = reversiMap[x][y];
}
}
nowPage++;
lastPage = nowPage;
undoButton.enabled=true;
redoButton.enabled=false;
}
private function undo():void{
if(nowPage == lastPage){
page[nowPage] = new Array();
for(var x:uint=0;x<8;x++){
page[nowPage][x] = new Array();
for(var y:uint=0;y<8;y++){
page[nowPage][x][y] = reversiMap[x][y];
}
}
}
nowPage--;
redoButton.enabled=true;
if(nowPage == 0){
undoButton.enabled=false;
}
gotoNowPage();
}
private function redo():void{
nowPage++;
undoButton.enabled=true;
if(nowPage == lastPage){
redoButton.enabled=false;
}
gotoNowPage();
}
private function gotoNowPage():void{
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
reversiMap[x][y] = page[nowPage][x][y];
}
}
setField();
}
private function click(e:MouseEvent):void{
var x:int = e.localX / size;
var y:int = e.localY / size;
if(x>=0 && x<othelloSize && y>=0 && y<othelloSize && player[nowTurn]==0){
if(placable(x,y,nowTurn,reversiMap)){
addNewPage();
place(x,y);
}
}
}
//reversiMapのデータをfieldに反映
private function setField():void{
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
cell[x][y].selectedIndex = reversiMap[x][y];
}
}
}
//(x,y)に石を置いたとき何が起こるかを返す。
private function placeData(x:uint,y:uint,t:uint,mapData:Vector.<Vector.<uint>>):Object{
var object:Object = new Object();
object.mapData =new Vector.<Vector.<uint>>(8);
for(var ax:uint=0;ax<8;ax++){
object.mapData[ax] = new Vector.<uint>(8);
for(var ay:uint=0;ay<8;ay++){
object.mapData[ax][ay] = mapData[ax][ay];
}
}
object.counter = 0;
if(finish || cell[x][y].selectedIndex != 0){
return object;
}
for(var dx:int = -1; dx <= 1; dx++){
for(var dy:int = -1; dy <= 1; dy++){
var sx:int = x;
var sy:int = y;
var count:uint=0;
while(true){
sx+=dx; sy+=dy;
if(sx<0 || sx>=othelloSize || sy<0 || sy>=othelloSize || mapData[sx][sy] == 0){
count=0;
break;
}else if(mapData[sx][sy] == t){
break;
}
count++;
}
if(count > 0){
sx = x;
sy = y;
for(var i:int = 0;i<=count;i++){
object.counter++;
object.mapData[sx][sy] = t;
sx+=dx; sy+=dy;
}
}
}
}
return object;
}
private function place(x:uint,y:uint):void{
var next:Object = placeData(x,y,nowTurn,reversiMap);
if(next.counter > 0){
nowTurn = 3 - nowTurn;
passNumber=0;
reversiMap = next.mapData;
setField();
output();
}
}
private function placable(x:uint,y:uint,t:int,mapData:Vector.<Vector.<uint>>):Boolean{
if(mapData[x][y] != 0){ return false; }
for(var dx:int = -1; dx <= 1; dx++){
for(var dy:int = -1; dy <= 1; dy++){
var sx:int = x;
var sy:int = y;
var count:uint=0;
while(true){
sx+=dx; sy+=dy;
if(sx<0 || sx>=othelloSize || sy<0 || sy>=othelloSize || mapData[sx][sy] == 0){
count=0;
break;
}else if(mapData[sx][sy] == t){
break;
}
count++;
}
if(count > 0){
return true;
}
}
}
return false;
}
private function passable():Boolean{
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
if(placable(x,y,nowTurn,reversiMap)){ return false; }
}
}
return true;
}
private function pass():void{
if(passable()){
passNumber++;
nowTurn = 3 - nowTurn;
output();
Alert.show("パスしました", "パス", (Alert.OK), this);
}else{
Alert.show("まだ打てるところがあります。\nパスはできません", "パス", (Alert.OK), this);
}
}
private function output():void{
blackNumber=0;
whiteNumber=0;
timer = 0;
finish = true;
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
if(cell[x][y].selectedIndex == 1){
blackNumber++;
}else if(cell[x][y].selectedIndex == 2){
whiteNumber++;
}else if(cell[x][y].selectedIndex == 0 && finish){
if(placable(x,y,1,reversiMap) || placable(x,y,2,reversiMap)){
finish = false;
}
}
}
}
if(player[1]==0){
if(yourTurn == 1){
blackLabel.text="あなた";
}else if(yourTurn == 2){
blackLabel.text="相手";
}
}else if(0<player[1] && player[1]<10){
blackLabel.text="COM";
}
if(player[2]==0){
if(yourTurn == 2){
whiteLabel.text="あなた";
}else if(yourTurn == 1){
whiteLabel.text="相手";
}
}else if(0<player[2] && player[2]<10){
whiteLabel.text="COM";
}
blackLabel.text += " :" + blackNumber;
whiteLabel.text += " :" + whiteNumber;
if(nowTurn == 1){
blackCanvas.filters = [glow];
whiteCanvas.filters = [blur];
}else if(nowTurn == 2){
whiteCanvas.filters = [glow];
blackCanvas.filters = [blur];
}
if(finish == true){
gameOver();
}
}
private function gameOver():void{
var s:String = blackNumber +":"+ whiteNumber+" ";
if((yourTurn == 1) == (blackNumber > whiteNumber) ){
s += "あなたの勝ちです。";
}else if((yourTurn == 2) == (blackNumber > whiteNumber) ){
s += "あなたの負けです。";
}else{
s += "引き分けです";
}
Alert.show(s,"GAME OVER");
passButton.enabled = false;
removeEventListener(Event.ENTER_FRAME,cp);
}
private function cp(e:Event):void{
if(nowTurn != yourTurn && finish==false){
if(timer > 20){
switch(player[nowTurn]){
case 1:
easyAI();
timer=0;
break;
case 2:
normalAI();
timer=0;
break;
case 3:
hardAI();
timer=0;
break;
case 4:
veryhardAI();
timer=0;
break;
case 5:
hardestAI();
timer=0;
break;
}
}
timer++;
}else{
timer = 0;
}
}
private function easyAI():void{
if(passable()){
pass();
return;
}
var max:int = 0;
var maxY:uint = 0;
var maxX:uint = 0;
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
var next:Object = placeData(x,y,nowTurn,reversiMap);
var point:int = next.counter;
if(point > 0){
if(((x<2||5<x)&&(y<2||5<y))==false){
point+=100;
}
if(x==0 || 7==x){
if(y==0 ||7==y){
point +=200;
}
}
}
if(max < point){
max = point;
maxX = x;
maxY = y;
}else if(max == point){
var r:Number = rand*(nowPage+1);
r = r - Math.floor(r);
if(r < 0.5){
maxX = x;
maxY = y;
}
}
}
}
place(maxX,maxY);
}
private function normalAI():void{
if(passable()){
pass();
return;
}
var max:int = 0;
var maxY:uint = 0;
var maxX:uint = 0;
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
var next:Object = placeData(x,y,nowTurn,reversiMap);
var point:int = next.counter;
if(point > 0){
if(((x<2||5<x)&&(y<2||5<y))==false){
point =100-point;
}
if(x==0 || 7==x){
if(y==0 ||7==y){
point +=200;
}
}
}
if(max < point){
max = point;
maxX = x;
maxY = y;
}else if(max == point){
var r:Number =rand*(nowPage+1);
r = r - Math.floor(r);
if(r < 0.5){
maxX = x;
maxY = y;
}
}
}
}
place(maxX,maxY);
}
private function hardAI():void{
if(passable()){
pass();
}
if(passable()){
pass();
return;
}
var max:int = 0;
var maxY:uint = 0;
var maxX:uint = 0;
for(var x:uint=0;x<8;x++){
for(var y:uint=0;y<8;y++){
var next:Object = placeData(x,y,nowTurn,reversiMap);
var point:int = next.counter;
if(point > 0){
if(((x<2||5<x)&&(y<2||5<y))==false){
point =1000-point;
}else{
point +=900;
}
if(x==0 || 7==x){
if(y==0 ||7==y){
point +=1500;
}
}
for(var ax:uint=0;ax<8;ax++){
for(var ay:uint=0;ay<8;ay++){
if(placable(ax,ay,nowTurn,next.mapData)){
point+=3;
}
if(placable(ax,ay,3-nowTurn,next.mapData)){
point-=6;
}
}
}
}
if(max < point){
max = point;
maxX = x;
maxY = y;
}else if(max == point){
var r:Number =rand*(nowPage+1);
r = r - Math.floor(r);
if(r < 0.5){
maxX = x;
maxY = y;
}
}
}
}
place(maxX,maxY);
}
//だれかがつくるかもしれないAI
private function veryhardAI():void{
//if(passable()){pass();return;}
//place(.......);
}
private function hardestAI():void{
//if(passable()){pass();return;}
//place(.......);
}
]]></mx:Script>
<!-- Alert用のBox -->
<mx:Box id="config" includeInLayout="false" horizontalAlign="left" height="100%" width="100%"
paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" >
<mx:Label text="対戦相手の設定"/>
<mx:HBox>
<mx:RadioButtonGroup id="player2" selectedValue="1"/>
<mx:RadioButton groupName="player2" value="0" label="人"/>
<mx:RadioButton groupName="player2" value="1" label="COMレベル1"/>
</mx:HBox>
<mx:HBox>
<mx:RadioButton groupName="player2" value="2" label="COMレベル2" />
<mx:RadioButton groupName="player2" value="3" label="COMレベル3" />
</mx:HBox>
<!--
<mx:HBox>
<mx:RadioButton groupName="player2" value="4" label="COMレベル4" />
<mx:RadioButton groupName="player2" value="5" label="COMレベル5" />
</mx:HBox>
-->
<mx:Spacer height="10"/>
<mx:Label text="あなたの手順"/>
<mx:HBox >
<mx:RadioButtonGroup id="selectTurn" selectedValue="1"/>
<mx:RadioButton groupName="selectTurn" value="1" label="先手"/>
<mx:RadioButton groupName="selectTurn" value="2" label="後手"/>
</mx:HBox>
</mx:Box>
<!-- 盤面 -->
<mx:HBox id="field" borderStyle="solid" horizontalGap="0" borderColor="0x000000" backgroundColor="0x00CC00" />
<mx:HBox horizontalGap="2" width="85%" horizontalAlign="center" >
<mx:Button label="新しいゲーム" height="30" click="newGame();"/>
<mx:Spacer width="20"/>
<mx:Button id="passButton" label="パス" height="30" click="pass();"/>
<mx:Spacer width="20"/>
<mx:Button id="undoButton" label="一つ戻る" enabled="false" height="30" click="undo();" />
<mx:Button id="redoButton" label="やり直し" enabled="false" height="30" click="redo();" />
</mx:HBox>
<mx:HBox horizontalGap="2" width="85%">
<mx:Canvas id="blackCanvas" borderStyle="solid" borderColor="0x222222" backgroundColor="0x00CC00">
<mx:UIComponent id="black" height="30" width="30"
creationComplete=" black.graphics.beginFill (0x000000, 1.0);
black.graphics.lineStyle (2, 0x000000, 1.0);
black.graphics.drawCircle (15, 15, 14);" />
</mx:Canvas>
<mx:Label id="blackLabel" text="" height="30" fontSize="20"/>
<mx:Spacer width="100%"/>
<mx:Label id="whiteLabel" text="" height="30" fontSize="20"/>
<mx:Canvas id="whiteCanvas" borderStyle="solid" borderColor="0x222222" backgroundColor="0x00CC00">
<mx:UIComponent id="white" height="30" width="30"
creationComplete=" white.graphics.beginFill (0xFFFFFF, 1.0);
white.graphics.lineStyle (2, 0x000000, 1.0);
white.graphics.drawCircle (15, 15, 14);" />
</mx:Canvas>
</mx:HBox>
</mx:Application>