Skip to content

Instantly share code, notes, and snippets.

@MikuroXina
Last active February 24, 2020 11:54
Show Gist options
  • Select an option

  • Save MikuroXina/a0e8889f886632f91257e644fc0f4363 to your computer and use it in GitHub Desktop.

Select an option

Save MikuroXina/a0e8889f886632f91257e644fc0f4363 to your computer and use it in GitHub Desktop.
// イベント駆動型プログラミング言語 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