Last active
February 24, 2020 11:54
-
-
Save MikuroXina/a0e8889f886632f91257e644fc0f4363 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // イベント駆動型プログラミング言語 Alyr (開発予定) | |
| /* | |
| 他の言語にホストしてもらって動作するスクリプト言語 | |
| 各イベントはシングルスレッド上で非同期実行される | |
| 状態 Outside に発行されるイベントはホストから購読できる | |
| */ | |
| value VirusKind = enum { Tiny, Normal, Huge, }; | |
| value Position = enum { Holder, Board = struct { int x; int y }, }; | |
| impl Position { | |
| operator==(Position r) -> bool { | |
| ret this.x == r.x && this.y == r.y; | |
| } | |
| Upper() -> Position { ret Position.Board(this.x, this.y - 1); } | |
| Under() -> Position { ret Position.Board(this.x, this.y + 1); } | |
| Left() -> Position { ret Position.Board(this.x - 1, this.y); } | |
| Right() -> Position { ret Position.Board(this.x + 1, this.y); } | |
| } | |
| entity Virus = struct { VirusKind kind; Position pos; bool isCracked; }; | |
| impl Virus { | |
| IsCracked() -> bool { return this.isCracked; } | |
| Crack() { this.isCracked = true; } | |
| } | |
| impl Set<Virus> { | |
| FromPosition(Position pos) -> Iter<Virus> { | |
| ret this.Find(v => v.pos == pos); | |
| } | |
| FromId(Virus.Id id) -> Opt<Virus> { | |
| ret this.Find(v => v.id == id).Bind(Opt); | |
| } | |
| } | |
| state Model { | |
| int W; | |
| int H; | |
| int holderX; | |
| Virus.Id heldId; // entity はその Id 型を持つ | |
| Set<Virus> crowd; | |
| } | |
| event Outside -> Model { | |
| Init(int width, int height) { W = width; H = height; } | |
| Transpose(int newHolderX) { holderX = newHolderX; } | |
| Manipulate() { | |
| if (heldId == Virus.Id.Null) { | |
| crowd.Find(v => v.pos.x == holderX) | |
| .Sort((a, b) => a.pos.y > b.pos.y) | |
| .Take(1) | |
| .For(front => { | |
| heldId = frond.id; // entity は暗黙のフィールド id を持つ | |
| Change(front, Position.Holder); | |
| }); | |
| ret; | |
| } | |
| crowd.Map(v => v.pos) | |
| .Find(p => p.x == holderX) | |
| .Add(Position.Board(holderX, 0)) | |
| .Sort((a, b) => a.y > b.y) | |
| .Take(1) | |
| .For(frontPos => | |
| crowd.FromId(heldId).For(held => | |
| Change(held, frontPos.Under()) | |
| ) | |
| ); | |
| } | |
| Fall() { | |
| int crowdHeight = crowd.Map(v => v.pos.y).Max(y); | |
| if (H <= crowdHeight) { | |
| GameOver(); | |
| ret; | |
| } | |
| crowd.Filter(v => v.pos != Holder).For(v => Move(v, v.pos.Under())); | |
| Range(1, W).For(x => | |
| [VirusKind.Tiny, VirusKind.Normal, VirusKind.Huge] | |
| .Shuffle() | |
| .Take(1) | |
| .For(kind => | |
| Spawn(Virus(kind, Position.Board(x, 1), false)) | |
| ) | |
| ); | |
| } | |
| } | |
| event Model -> Outside, Model { | |
| Spawn(Virus spawned) { | |
| crowd.Add(spawned); | |
| } | |
| Move(Virus changed, Position dst) { | |
| crowd.FromPosition(dst.Under()) | |
| .For(under => Move(under, changed.pos)); | |
| if (changed.pos == Holder && dst == Board) { | |
| crowd.FromPosition(dst.Upper()) | |
| .For(upper => Hit(changed, upper)); | |
| } | |
| changed.pos = dst; | |
| } | |
| Hit(Virus hitter, Virus hitten) { | |
| if (hitter.kind == Tiny && hitten.kind == Normal | |
| || hitter.kind == Normal && hitten.kind == Huge) { | |
| Absorb(hitter); | |
| Crack(hitten); | |
| } | |
| } | |
| Absorb(absorbed) { | |
| crowd.Remove(absorbed); | |
| } | |
| Crack(Virus cracked) { | |
| if (cracked.IsCracked()) { Break(cracked); } | |
| cracked.Crack(); | |
| } | |
| Break(Virus broken) { | |
| [Upper, Under, Left, Right].For(Dir => | |
| crowd.FromPosition(broken.pos.Dir()).For(neighbor => { | |
| if (neighbor.kind == broken.kind) { | |
| Chain(upper); | |
| } | |
| }) | |
| ); | |
| crowd.Remove(broken); | |
| } | |
| Chain(Virus toBreak) { | |
| Delay(130).Then(() => Break(toBreak)); | |
| } | |
| GameOver() {} | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment