/* * 男女男男女男女 * * - ルール * - 異性が向かい合うように座らせてください * - 左から詰めて座ります * - 同じグループを重複して使えます * - 男女の人数が一致したらパーティ開始 (クリア) です * * - 操作方法など * - 下 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(); } } 男女男男女男女