くま、ソリテアになる
古典的パズル「ソリテア」(2010-03-26)
--------------------------------
To do:
1) せめて Undo くらいサポートせにゃ
2) それなら棋譜を残すようしたい
3) PLAY AGAIN ボタンつけなきゃ
4) 手詰りかどうかの判定もしたい
--------------------------------
/**
* Copyright tenasaku ( http://wonderfl.net/user/tenasaku )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/izMD
*/
// 古典的パズル「ソリテア」(2010-03-26)
// --------------------------------
// To do:
// 1) せめて Undo くらいサポートせにゃ
// 2) それなら棋譜を残すようしたい
// 3) PLAY AGAIN ボタンつけなきゃ
// 4) 手詰りかどうかの判定もしたい
// --------------------------------
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Main extends Sprite {
private static const NO_DRAG:int = -1;
private static const _H:Number = 66.4;
private static const _V:Number = 66.4;
private static const _dimpleRadius:Number = 24;
private static const _boundsRect:Rectangle
= new Rectangle( 0, 0, _H*7, _V*7 );
private static const _bgColor:uint = 0xccff99;
private static const _dimpleColor:uint = 0xffffff;
private static const _borderColor:uint = 0x008000;
private var status:Array; // 各マス目の状態の配列
private var icon:Array; // 各マス目の表示オブジェクトの配列
private var dragged:KumaIcon; // ドラッグ中に表示されるオブジェクト
private var dragFrom:int; // どのマス目からドラッグを開始したかを記憶
private var lastMove:uint; // 直前の一手を記憶
// どのマス目がクリックされたかを判定する
private function whichDimple(e:MouseEvent):int {
var i:int,result:int;
i = 0;
while ( i < 49 ) {
var h:int = i%7;
var v:int = Math.floor(i/7);
var dx:Number = e.stageX - _H*(h+0.5);
var dy:Number = e.stageY - _V*(v+0.5);
if ( Math.sqrt(dx*dx+dy*dy) < _dimpleRadius ) {
result = i;
break;
} else {
result = NO_DRAG;
++i;
}
}
return result;
}
// ボードの状態と表示の初期化
private function initBoard():void {
var i:int,h:int,v:int;
status = new Array(49);
icon = new Array(49);
for ( i = 0; i < 49; ++i ) {
h = i%7;
v = Math.floor(i/7);
if ( ( Math.abs(h-3)< 2 ) || ( Math.abs(v-3)< 2 ) ) {
status[i] = ( (h==3)&&(v==3) )?0:1;
icon[i] = new KumaIcon();
icon[i].x = _H*(h+0.5);
icon[i].y = _V*(v+0.5);
icon[i].visible = !(status[i] == 0);
this.addChild(icon[i]);
this.graphics.lineStyle(3,_borderColor);
this.graphics.beginFill(_dimpleColor);
this.graphics.drawCircle(icon[i].x,icon[i].y,_dimpleRadius);
this.graphics.endFill();
} else {
status[i] = 2;
icon[i] = null;
}
}
}
// マウスボタンが押されたとき
private function onMouseDown(e:MouseEvent):void {
dragged.x = e.stageX;
dragged.y = e.stageY;
dragFrom = whichDimple(e);
if ( (dragFrom != NO_DRAG) && (status[dragFrom] == 1) ) {
icon[dragFrom].visible = false;
dragged.visible = true;
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
dragged.startDrag(false,_boundsRect);
} else {
dragFrom = NO_DRAG;
}
}
// マウスボタンが離されたとき
private function onMouseUp(e:MouseEvent):void {
dragged.stopDrag();
dragged.visible = false;
var dragTo:int = whichDimple(e);
if ( moveOK(dragFrom,dragTo) ) {
makeMove(dragFrom,dragTo);
} else {
if ( dragFrom != NO_DRAG ) {
icon[dragFrom].visible = true;
}
}
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
// ドラッグ中
private function onMouseMove(e:MouseEvent):void {
e.updateAfterEvent();
}
// i1 から i2 への動きが可能か判定
private function moveOK(i1:int,i2:int):Boolean {
if ( ( i1 < 0 ) || ( i1 >= 49 ) ) { // 出発点が盤上にない
return false;
}
if ( ( i2 < 0 ) || ( i2 >= 49 ) ) { // 行き先が盤上にない
return false;
}
var h1:int = i1%7;
var v1:int = Math.floor(i1/7);
var h2:int = i2%7;
var v2:int = Math.floor(i2/7);
if ( Math.max(Math.abs(h1-h2),Math.abs(v1-v2)) != 2 ) { // 二個となりでない
return false;
}
if ( (h1 != h2) && (v1 != v2) ) { // 同じ列や行にない
return false;
}
if ( ( status[i1] != 1 ) ) { // 出発点に玉がない
return false;
}
if ( ( status[i2] != 0 ) ) { // 行き先にすでに玉がある
return false;
}
if ( status[(i1+i2)>>1] != 1 ) { // あいだの一個がない
return false;
}
// 以上のどれでもないときだけ, 真を返す
return true;
}
// i1 から i2 への実際の移動処理
// ここでは条件のチェックはしない
private function makeMove(i1:int,i2:int):void {
status[i1] = 0;
status[i2] = 1;
status[(i1+i2)>>1] = 0;
icon[i1].visible = false;
icon[i2].visible = true;
icon[(i1+i2)>>1].visible = false;
lastMove = (i1 & 63)<<8|(i2 & 63);
}
// プログラム全体の初期化動作
private function initialize(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
// 全体を背景色で塗る
this.graphics.clear();
this.graphics.lineStyle(NaN);
this.graphics.beginFill(_bgColor);
this.graphics.drawRect(0,0,_H*7,_V*7);
this.graphics.endFill();
// グローバル変数の初期化
dragFrom = NO_DRAG;
lastMove = 0;
// ボードの初期化と表示
initBoard();
// ドラッグ中のアイコンの初期化と非表示設定
dragged = new KumaIcon();
dragged.visible = false;
this.addChild(dragged);
// イベントリスナーの登録
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
// エントリー・ポイント
public function Main():void {
if ( stage != null ) {
initialize(null);
} else {
this.addEventListener(Event.ADDED_TO_STAGE, initialize);
}
}
} // end of class Main
} // end of package
// クマ顔アイコン 新バージョン
import flash.display.*;
class KumaIcon extends Sprite {
private static const _borderColor:uint = 0x000000;
private static const _fillColor:uint = 0x800000;
public function KumaIcon():void {
this.graphics.clear();
this.graphics.lineStyle(NaN);
this.graphics.beginFill(_fillColor);
this.graphics.drawCircle(0,0,20);
this.graphics.endFill();
this.graphics.beginFill(_fillColor);
this.graphics.drawCircle(14,-14,8);
this.graphics.endFill();
this.graphics.beginFill(_fillColor);
this.graphics.drawCircle(-14,-14,8);
this.graphics.endFill();
this.graphics.beginFill(0xffffff);
this.graphics.drawEllipse(-8,0,16,15);
this.graphics.endFill();
this.graphics.beginFill(_borderColor);
this.graphics.drawEllipse(-2,2,4,3);
this.graphics.endFill();
this.graphics.beginFill(_borderColor);
this.graphics.drawEllipse(-12,-5,3,4);
this.graphics.endFill();
this.graphics.beginFill(_borderColor);
this.graphics.drawEllipse( 12,-5,-3,4);
this.graphics.endFill();
this.graphics.lineStyle(1,_borderColor);
this.graphics.moveTo(-4, 12);
this.graphics.curveTo( 0, 10, 0, 6);
this.graphics.curveTo( 0, 10, 4, 12);
}
}