男女男男女男女
男女男男女男女
*
* - ルール
* - 異性が向かい合うように座らせてください
* - 左から詰めて座ります
* - 同じグループを重複して使えます
* - 男女の人数が一致したらパーティ開始 (クリア) です
*
* - 操作方法など
* - 下 3 つのグループボタンをクリックすると座ります
* - "1" "2" "3" や "z" "x" "c" キーでもいいです
* - undo は "u" か BS
* - 全 5 面です (ちゃんと解けます)
/**
* Copyright wondermame ( http://wonderfl.net/user/wondermame )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wcnb
*/
/*
* 男女男男女男女
*
* - ルール
* - 異性が向かい合うように座らせてください
* - 左から詰めて座ります
* - 同じグループを重複して使えます
* - 男女の人数が一致したらパーティ開始 (クリア) です
*
* - 操作方法など
* - 下 3 つのグループボタンをクリックすると座ります
* - "1" "2" "3" や "z" "x" "c" キーでもいいです
* - undo は "u" か BS
* - 全 5 面です (ちゃんと解けます)
*/
package {
import flash.display.Sprite;
import flash.events.KeyboardEvent;
import net.wonderfl.score.basic.BasicScoreForm;
import net.wonderfl.score.basic.BasicScoreRecordViewer;
public class main extends Sprite {
public function main() {
stage.align = "TL";
stage.scaleMode = "noScale";
var game:Game = new Game(stage.stageWidth / 10, stage.stageHeight / 10, view, submit);
addChild(game);
stage.addEventListener(KeyboardEvent.KEY_DOWN, game.keydown);
}
private function view():void {
var x: int = (stage.stageWidth - BasicScoreRecordViewer.WIDTH ) / 2;
var y: int = (stage.stageHeight - BasicScoreRecordViewer.HEIGHT) / 2;
new BasicScoreRecordViewer(this, x, y, "RANKING", 50);
}
private function submit(party:int):void {
var x: int = (stage.stageWidth - BasicScoreForm.WIDTH ) / 2;
var y: int = (stage.stageHeight - BasicScoreForm.HEIGHT) / 2;
new BasicScoreForm(this, x, y, party, "YOUR SCORE");
}
}
}
import flash.geom.Matrix;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextFieldAutoSize;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Graphics;
import flash.display.SimpleButton;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
class Game extends Sprite {
/* 問題データ */
private var parties:Array = [
[ ["a","aa"], ["aaa","a"], ["aa","bb"] ],
[ ["a","baaa"], ["a","ab"], ["aba","a"] ],
[ ["abb","a"], ["b","abb"], ["a","bb"] ],
[ ["abb","a"], ["b","abb"], ["a","b"] ],
[ ["baab","b"], ["a","aab"], ["ab","a"] ],
];
private var party:int = 0; // 現在の問題の番号
private var pairs:Array; // 現在の問題
private var upper:String, lower:String; // 上下の列の状態
private var moves:Array; // 今までの手順
private var clear:Boolean; // クリア状態のフラグ
private var depth:int; // 画面からはみ出ている数
private var screen:Sprite; // 上下の列を持つダミースプライト
private var groups:Array; // 表示されている Group 群
private var uppers:Array, lowers:Array; // 上下の列に表示されている Person 群
private var unmatched_marks:Array; // ×マークの UnmatchedMark 群
private var heart_marks:Array; // ハートマーク
private var buttons:Array; // ボタン 4 つ
private var upper_vgroups:Array; // 上側のプレビュー Group 3 つ
private var lower_vgroups:Array; // 下側のプレビュー Group 3 つ
private var unmatched:Array; // プレビュー Group で×マークが出る位置
private var count:int; // マークアニメーション用カウンタ
private var screen_scale:Number; // 論理上の screen 縮尺
private var screen_x:Number; // 論理上の screen 位置
private var screen_count:int; // screen アニメーション用カウンタ
private var party_name:TextField; // 問題番号表示
private var clear_msg:TextField; // クリアメッセージ表示
private var traceField:TextField;
private var view:Function, submit:Function; // スコア
public function Game(_scaleX:Number, _scaleY:Number, _view:Function, _submit:Function) {
// 画面の基本的な初期化
scaleX = _scaleX;
scaleY = _scaleY;
view = _view;
submit = _submit;
var g:Graphics = this.graphics;
g.beginFill(0x333333);
g.drawRect(0, 0, 10, 10);
g.endFill();
traceField = create_text("", 20, 10, 1);
this.addChild(traceField);
// イベントハンドラ設定
count = screen_count = 0;
addEventListener(Event.ENTER_FRAME, animate);
// ステージ番号
party_name = create_text("", 20, 10, 1);
party_name.y = 1;
addChild(party_name);
// クリアメッセージ表示
clear_msg = create_text("", 30, 10, 1);
clear_msg.y = 4.5;
addChild(clear_msg);
// ゲームスタート
party = 0;
setup();
}
// 各問題の初期化
private function setup():void {
clear = false;
depth = 0;
pairs = parties[party];
upper = "";
lower = "";
moves = [];
screen = new Sprite();
addChild(screen);
groups = [];
uppers = [];
lowers = [];
unmatched_marks = [];
heart_marks = [];
upper_vgroups = [];
lower_vgroups = [];
buttons = [];
unmatched = [];
make_buttons();
make_groups();
make_unmatched();
screen.y = 2;
update();
party_name.text = "Party " + (party + 1) + " / " + parties.length;
clear_msg.text = "";
}
// 各問題の廃棄
private function dispose():void {
var i:int;
for (i = 0; i < buttons.length; i++) {
removeChild(buttons[i]);
}
removeChild(screen);
Person.clear();
}
// 問題クリア
private function next_party():void {
dispose();
if (++party == parties.length) {
submit(party);
party = 0;
}
setup();
}
// 画面構成補助: TextField 作成
private function create_text(msg:String, weight:int, width:Number, height:Number):TextField {
var text:TextField = new TextField();
text.width = width * scaleX;
text.height = height * scaleY;
var format:TextFormat = new TextFormat();
format.align = TextFormatAlign.CENTER;
format.size = weight;
format.color = 0xffffff;
text.defaultTextFormat = format;
text.selectable = false;
text.scaleX = 1 / scaleX;
text.scaleY = 1 / scaleY;
text.text = msg;
return text;
}
// 画面構成補助: SimpleButton 作成
private function create_button(x:Number, y:Number, make_state:Function, click:Function):SimpleButton {
var button:SimpleButton = new SimpleButton();
button.x = x;
button.y = y;
var state:Sprite = make_state();
state.alpha = 0.5;
button.upState = state;
state = make_state();
button.overState = button.downState = button.hitTestState = state;
buttons.push(button);
addChild(button);
button.addEventListener(MouseEvent.CLICK, click);
return button;
}
// 画面構成: ボタン
private function make_buttons():void {
var idx:int, margin:Number, x:Number;
var button:SimpleButton;
// マージンの計算
for (idx = 0, margin = 10; idx < 3; idx++) {
margin -= Math.max(pairs[idx][0].length, pairs[idx][1].length);
}
margin /= 4;
// 問題の配置
x = margin;
for (idx = 0; idx < 3; idx++) {
button = create_button(x, 6, function():Sprite {
return new Button(idx, pairs[idx]);
}, create_callback(move, idx));
button.addEventListener(MouseEvent.MOUSE_OUT , create_callback(preview, -1));
button.addEventListener(MouseEvent.MOUSE_OVER, create_callback(preview, idx));
x += Math.max(pairs[idx][0].length, pairs[idx][1].length) + margin;
}
function create_callback(func:Function, arg:int):Function {
return function():void { func(arg); };
}
// Undo ボタンの配置
button = create_button(1, 8.25, make_button_shape("undo", 8, 0.5), function():void { undo(); });
button = create_button(1, 9, make_button_shape("view ranking", 3.75, 0.5), function():void { view(); });
button = create_button(5.25, 9, make_button_shape("submit your score", 3.75, 0.5), function():void { submit(party); });
function make_button_shape(msg: String, width:Number, height:Number):Function {
return function():Sprite {
var sprite:Sprite = new Sprite();
var g:Graphics = sprite.graphics;
g.beginFill(0x999999);
g.drawRoundRect(0, 0, width, height, 0.5);
g.endFill();
var text:TextField = create_text(msg, 20, width, height);
sprite.addChild(text);
return sprite;
};
}
}
// 画面構成: プレビュー用グループ
private function make_groups():void {
var idx:int;
for (idx = 0; idx < 3; idx++) {
upper_vgroups[idx] = new Group(pairs[idx][0], screen, null, true , true, idx);
lower_vgroups[idx] = new Group(pairs[idx][1], screen, null, false, true, idx);
}
}
// 画面構成: ×マーク
private function make_unmatched():void {
var i:int;
for (i = 0; i < 4; i++) {
var mark:UnmatchedMark = new UnmatchedMark(i);
unmatched_marks[i] = mark;
screen.addChild(mark);
}
}
// 配置変更後の状態更新
private function update():void {
var i:int, idx:int, next_depth:int;
// プレビュー用グループの再配置
for (idx = 0; idx < pairs.length; idx++) {
upper_vgroups[idx].x = uppers.length;
lower_vgroups[idx].x = lowers.length;
move(idx, unmatched[idx] = []);
}
// 画面からはみ出ている数の再設定
next_depth = Math.min(uppers.length, lowers.length);
// 配置の場合はハートマークを増やす
for (i = depth; i < next_depth; i++) {
var heart:HeartMark = new HeartMark();
screen.addChild(heart);
heart.x = i;
heart_marks.push(heart);
}
// undo の場合は浮かれ状態を解除する
for (i = next_depth; i < depth; i++) {
if (uppers[i]) uppers[i].redraw(0, 0);
if (lowers[i]) lowers[i].redraw(0, 0);
screen.removeChild(heart_marks.pop());
}
depth = next_depth;
// 縮尺の調整
// depth-1 より右が見えていないといけない
var bottom:int = depth - 1;
// Math.min(uppers.length, lowers.length) + 5 より左が見えていないといけない
// Math.max(uppers.length, lowers.length) + 1 より左が見えていないといけない
var top:int = Math.max(Math.min(uppers.length, lowers.length) + 4, uppers.length, lowers.length) + 1;
// 余裕があれば調整
if (top < bottom + 10) bottom = top - 10;
if (bottom < 0) { bottom = 0; top = 10; }
screen_scale = 10.0 / (top - bottom);
screen_x = -bottom * screen_scale;
screen_count = 8;
// プレビュー用グループを一旦消す
preview(-1);
}
// 配置
private function move(idx:int, test:Array=null):void {
if (clear) return;
var upper2:String = upper + pairs[idx][0];
var lower2:String = lower + pairs[idx][1];
var i:int, end:int = Math.min(upper2.length, lower2.length);
var well:Boolean = true;
for (i = 0; i < end; i++) {
if (upper2.charAt(i) != lower2.charAt(i)) {
well = false;
if (test) test[i] = true; else break;
}
}
if (!test && well) {
upper = upper2.substring(end);
lower = lower2.substring(end);
moves.push(idx);
groups.push(new Group(pairs[idx][0], screen, uppers, true , false, idx));
groups.push(new Group(pairs[idx][1], screen, lowers, false, false, idx));
if (upper.length == 0 && lower.length == 0) {
clear = true;
clear_msg.text = "Let's party!";
}
update();
}
}
// 配置の取り消し
private function undo():void {
if (clear || moves.length == 0) return;
var i:int, idx:int = moves.pop();
var upper2:String = pairs[idx][0];
var lower2:String = pairs[idx][1];
var upper_len:int = upper2.length - upper.length;
var lower_len:int = lower2.length - lower.length;
var len:int = Math.min(upper_len, lower_len);
if (len > 0) {
lower = upper2.substring(0, upper_len - len);
upper = lower2.substring(0, lower_len - len);
}
else {
if (upper.length > 0) {
upper = lower2 + upper.substring(0, -upper_len);
lower = "";
}
else {
lower = upper2 + lower.substring(0, -lower_len);
upper = "";
}
}
for (i = 0; i < upper2.length; i++) uppers.pop();
for (i = 0; i < lower2.length; i++) lowers.pop();
screen.removeChild(groups.pop());
screen.removeChild(groups.pop());
update();
}
// 配置のプレビュー
private function preview(idx:int):void {
var idx2:int;
if (clear) idx = -1;
for (idx2 = 0; idx2 < pairs.length; idx2++) {
upper_vgroups[idx2].visible = (idx == idx2);
lower_vgroups[idx2].visible = (idx == idx2);
}
var i:int;
for (i = 0; i < 4; i++) {
if (idx >= 0 && unmatched[idx][i]) {
unmatched_marks[i].visible = true;
unmatched_marks[i].x = depth + i;
screen.addChildAt(unmatched_marks[i], screen.numChildren - 1);
}
else {
unmatched_marks[i].visible = false;
}
}
}
// キー押下イベントハンドラ
public function keydown(e:KeyboardEvent):void {
switch (e.keyCode) {
case 85: case 8: undo(); break;
case 49: case 97: case 90: preview(0); move(0); break;
case 50: case 98: case 88: preview(1); move(1); break;
case 51: case 99: case 67: preview(2); move(2); break;
case 72: Person.toggle(); break;
}
}
// 画面の更新
private function animate(e:Event):void {
if (screen_count > 0) {
var factor:Number = 6 / (screen_count + 1) / (2 * screen_count + 1);
screen.scaleX += (screen_scale - screen.scaleX) * factor;
screen.x += (screen_x - screen.x) * factor;
screen_count--;
}
else if (clear) {
screen.x += 0.25;
if (screen.x > 10) {
next_party();
}
}
count = (count + 1) % 24;
if (count == 0 || count == 12) {
var i:int = Math.max(depth - 10, 0);
var pulse:int = count == 12 ? 1 : -1;
if (clear) i = 0;
for (; i < depth; i++) {
if (uppers[i]) uppers[i].redraw(pulse, -1);
if (lowers[i]) lowers[i].redraw(pulse, 1);
var heart:HeartMark = heart_marks[i];
heart.x = pulse * 0.2 + i;
heart.y = pulse * 0.1;
}
}
}
}
// ペアを配置するボタン
class Button extends Sprite {
public function Button(idx:int, pair:Array) {
var g:Graphics = this.graphics;
g.beginFill(0x999999);
g.drawRoundRect(0, 0, Math.max(pair[0].length, pair[1].length), 2, 0.2);
g.endFill();
addChild(new Group(pair[0], null, null, true , false, idx));
addChild(new Group(pair[1], null, null, false, false, idx));
}
}
// 数人を角丸四角で囲んだグループ
class Group extends Sprite {
private var color:Array = [ 0xffcccc, 0xccffcc, 0xccccff ];
public function Group(seq:String, screen:Sprite, persons:Array, upper_p:Boolean, virtual_p:Boolean, background:int) {
if (screen) screen.addChild(this);
var y:int = upper_p ? 0 : 1;
var g:Graphics = this.graphics;
g.beginFill(color[background]);
g.drawRoundRect(0.05, y + 0.05, seq.length - 0.1, 0.9, 0.5);
g.endFill();
if (persons) this.x = persons.length;
if (virtual_p) this.alpha = 0.3;
var i:int;
for (i = 0; i < seq.length; i++) {
var person:Person = new Person(seq.charAt(i) == "a", upper_p);
addChild(person);
person.x = i;
person.y = y;
if (persons) persons.push(person);
}
}
}
// 男または女
class Person extends Sprite {
private static var all_sprites:Array = [], hetero:Boolean = true;
private var sprite:Sprite;
private var male_p:Boolean, upper_p:Boolean;
public function Person(male_p:Boolean, upper_p:Boolean) {
all_sprites.push(this);
this.male_p = male_p;
this.upper_p = upper_p;
sprite = new Sprite();
addChild(sprite);
sprite.x = sprite.y = 0.5;
draw();
}
private function draw():void {
var g:Graphics = sprite.graphics;
g.clear();
g.beginFill((male_p == upper_p) || !hetero ? 0x0000ff : 0xff0000);
g.drawCircle(0, -0.2, 0.15);
if (male_p == upper_p) {
g.moveTo(0, 0.35);
g.lineTo(-0.2, -0.05);
g.lineTo(0.2, -0.05);
g.lineTo(0, 0.35);
}
else {
g.moveTo(0, -0.05);
g.lineTo(-0.2, 0.35);
g.lineTo(0.2, 0.35);
g.lineTo(0, -0.05);
}
g.endFill();
}
public function redraw(type:int, slide:int):void {
var mat:Matrix = sprite.transform.matrix;
mat.c = -0.3 * type;
sprite.transform.matrix = mat;
sprite.y = 0.5 - 0.15 * slide;
}
public static function toggle():void {
var i:int;
hetero = !hetero;
for (i = 0; i < all_sprites.length; i++) {
all_sprites[i].draw();
}
}
public static function clear():void {
while (all_sprites.length > 0) all_sprites.pop();
}
}
// ×マーク
class UnmatchedMark extends Sprite {
public function UnmatchedMark(x:int) {
this.x = x;
this.y = 0.5;
var g:Graphics = this.graphics;
g.beginFill(0x990000);
g.moveTo(0.1, 0.0);
g.lineTo(0.5, 0.4);
g.lineTo(0.9, 0.0);
g.lineTo(1.0, 0.1);
g.lineTo(0.6, 0.5);
g.lineTo(1.0, 0.9);
g.lineTo(0.9, 1.0);
g.lineTo(0.5, 0.6);
g.lineTo(0.1, 1.0);
g.lineTo(0.0, 0.9);
g.lineTo(0.4, 0.5);
g.lineTo(0.0, 0.1);
g.lineTo(0.1, 0.0);
g.endFill();
}
}
// ハートマーク
class HeartMark extends Sprite {
public function HeartMark() {
var g:Graphics = this.graphics;
g.lineStyle(0, 0xcc0000);
g.beginFill(0xff6666);
g.moveTo(0.5, 0.85);
g.curveTo(0.61,0.74,0.66,0.84);
g.curveTo(0.70,0.96,0.5,1.08);
g.curveTo(0.30,0.96,0.34,0.84);
g.curveTo(0.39,0.74,0.5,0.85);
g.endFill();
}
}