Created
December 3, 2023 14:23
-
-
Save takoeight0821/f332804e582078b5fc8af6b04eb13333 to your computer and use it in GitHub Desktop.
RPG EDSL
This file contains 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
// アイテムやスキルの効果を、プログラム上のデータとして表現し、それを解釈・実行することで各パラメータを算出する。 | |
// EDSL (Embedded Domain Specific Language 組み込みDSL) として知られているテクニック。 | |
namespace Edsl | |
{ | |
// Stats represents parameters of the character. | |
// Stats can only be calculated by Effect.execute() method. | |
record Stats(string Name, int HP, int MP, int ATK, int DEF); | |
// Condition represents the condition of the game. | |
// Condition can be calculated by Effect.execute() method. | |
// Condition also can be constructed by whole game routine. | |
abstract record Condition | |
{ | |
abstract public bool Satisfies(Condition given); | |
public record Grabbed(Stats Enemy) : Condition | |
{ | |
public override bool Satisfies(Condition given) | |
{ | |
return given switch | |
{ | |
Grabbed grabbed => Enemy.Name == grabbed.Enemy.Name, | |
_ => false | |
}; | |
} | |
} | |
} | |
// Effect represents the effect of items or skills. | |
abstract record Effect | |
{ | |
// execute() method calculates the stats and condition. | |
abstract public (Stats, Condition) Execute(Stats stats, Condition given); | |
// Damage represents the damage to stats. | |
public record Damage(int Value) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
return (stats with { HP = stats.HP - (Value - stats.DEF) }, given); | |
} | |
} | |
public record Heal(int Value) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
return (stats with { HP = stats.HP + Value }, given); | |
} | |
} | |
public record Charge(int Value) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
return (stats with { MP = stats.MP + Value }, given); | |
} | |
} | |
public record Buff(int Value) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
return (stats with { ATK = stats.ATK + Value }, given); | |
} | |
} | |
public record Guard(int Value) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
return (stats with { DEF = stats.DEF + Value }, given); | |
} | |
} | |
public record When(Condition Want, Effect Effect) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
if (given.Satisfies(Want)) | |
{ | |
return Effect.Execute(stats, given); | |
} | |
else | |
{ | |
return (stats, given); | |
} | |
} | |
} | |
public record Then(Effect First, Effect Second) : Effect | |
{ | |
public override (Stats, Condition) Execute(Stats stats, Condition given) | |
{ | |
var (stats1, given1) = First.Execute(stats, given); | |
return Second.Execute(stats1, given1); | |
} | |
} | |
} | |
} | |
namespace Game | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var player = new Edsl.Stats("Player", 100, 100, 20, 0); | |
Console.WriteLine($"Player: {player}"); | |
var enemy = new Edsl.Stats("Enemy", 45, 0, 20, 0); | |
Console.WriteLine($"Enemy: {enemy}"); | |
var buffItem = new Edsl.Effect.Buff(10); | |
var guardItem = new Edsl.Effect.Guard(10); | |
// attack 10 damage, then attack 20 damage if grabbed | |
var grabAttack = (Edsl.Stats player) => new Edsl.Effect.Then( | |
new Edsl.Effect.Damage(player.ATK), | |
new Edsl.Effect.When( | |
new Edsl.Condition.Grabbed(enemy), | |
new Edsl.Effect.Damage(player.ATK * 2) | |
) | |
); | |
// enemy is grabbed | |
var condition = new Edsl.Condition.Grabbed(enemy); | |
// player use buffItem | |
var (player1, condition1) = buffItem.Execute(player, condition); | |
Console.WriteLine($"Player use buffItem: {player1}"); | |
// enemy use guardItem | |
var (enemy1, condition2) = guardItem.Execute(enemy, condition1); | |
Console.WriteLine($"Enemy use guardItem: {enemy1}"); | |
// enemy attacked by player with grabAttack | |
// damage is (30 - 10) + (30 * 2 - 10) = 20 + 50 = 70 | |
var (enemy2, _) = grabAttack(player1).Execute(enemy1, condition2); | |
Console.WriteLine($"Enemy attacked: {enemy2}"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment