From be2f37a0678c66278d1c491b8f1250a8a3be9feb Mon Sep 17 00:00:00 2001 From: ywang Date: Wed, 3 Nov 2021 18:55:31 +0100 Subject: Support different types of speed restrictions; add documentation --- advtrains/doc/advtrains_speed_lessp.3advtrains.md | 15 ++++ .../doc/advtrains_speed_merge_aspect.3advtrains.md | 18 +++++ advtrains/init.lua | 4 +- advtrains/spec/speed_spec.lua | 70 +++++++++++++++++ advtrains/speed.lua | 88 ++++++++++++++++++++++ advtrains/trainlogic.lua | 5 +- 6 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 advtrains/doc/advtrains_speed_lessp.3advtrains.md create mode 100644 advtrains/doc/advtrains_speed_merge_aspect.3advtrains.md create mode 100644 advtrains/spec/speed_spec.lua create mode 100644 advtrains/speed.lua (limited to 'advtrains') diff --git a/advtrains/doc/advtrains_speed_lessp.3advtrains.md b/advtrains/doc/advtrains_speed_lessp.3advtrains.md new file mode 100644 index 0000000..165d028 --- /dev/null +++ b/advtrains/doc/advtrains_speed_lessp.3advtrains.md @@ -0,0 +1,15 @@ +% advtrains.speed.lessp(3advtrains) | Advtrains Developer's Manual + +# NAME +`advtrains.speed.lessp`, `advtrains.speed.greaterp`, `advtrains.speed.not_lessp`, `advtrains.speed_not_greaterp`, `advtrains.speed.equalp`, `advtrains.speed.not_equalp`, `advtrains.speed.max`, `advtrains.speed.min` - speed restriction comparison functions + +# SYNOPSIS +Each function takes two arguments and returns a boolean or (for `advtrains.speed.max` and `advtrains.speed.min`) a valid speed limit + +# DESCRIPTION + +The functions above correspond to the arithmetic `<`, `>`, `>=`, `<=`, `==`, `~=` operators and the `math.max` and `math.min` functions, respectively. The constants `nil` and `false` are treated as -1. + +# NOTES + +These functions are trivial to implement and the implementation can be easily embedded into existing code. They are simply provided for convenience. diff --git a/advtrains/doc/advtrains_speed_merge_aspect.3advtrains.md b/advtrains/doc/advtrains_speed_merge_aspect.3advtrains.md new file mode 100644 index 0000000..02e83ea --- /dev/null +++ b/advtrains/doc/advtrains_speed_merge_aspect.3advtrains.md @@ -0,0 +1,18 @@ +% advtrains.speed.set_restriction(3advtrains) | Advtrains Developer's Manual + +# NAME +`advtrains.speed.set_restriction`, `advtrains.speed.merge_aspect` - modify speed restriction + +# SYNOPSIS +* `advtrains.speed.set_restriction(train, rtype, rval)` +* `advtrains.speed.merge_aspect(train, asp)` + +# DESCRIPTION + +The `advtrains.speed.set_restriction` function sets the speed restriction of type `rtype` of `train` to `rval` and updates the speed restriction value to the strictest speed restriction in the table, or `nil` if all speed restrictions are `nil` or `-1`. If the speed restriction table does not exist, it is created with the `"main"` speed restriction being the speed restriction value of `train`. + +The `advtrains.speed.merge_aspect` function merges the main aspect of `asp` into the speed restriction table with the same procedure described above. If the signal aspect table does not provide the type of speed restriction, the restriction type `"main"` is assumed. + +# SIDE EFFECTS + +Both functions modify `train.speed_restriction` and `train.speed_restrictions_t`. diff --git a/advtrains/init.lua b/advtrains/init.lua index 0882237..a7e5764 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -198,6 +198,8 @@ advtrains.meseconrules = advtrains.fpath=minetest.get_worldpath().."/advtrains" +advtrains.speed = dofile(advtrains.modpath.."/speed.lua") + dofile(advtrains.modpath.."/path.lua") dofile(advtrains.modpath.."/trainlogic.lua") dofile(advtrains.modpath.."/trainhud.lua") @@ -467,7 +469,7 @@ advtrains.avt_save = function(remove_players_from_wagons) "trainparts", "recently_collided_with_env", "atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open", "text_outside", "text_inside", "line", "routingcode", - "il_sections", "speed_restriction", "is_shunt", + "il_sections", "speed_restriction", "speed_restrictions_t", "is_shunt", "points_split", "autocouple", "atc_wait_autocouple", "ars_disable", }) --then save it diff --git a/advtrains/spec/speed_spec.lua b/advtrains/spec/speed_spec.lua new file mode 100644 index 0000000..0f0365f --- /dev/null +++ b/advtrains/spec/speed_spec.lua @@ -0,0 +1,70 @@ +package.path = "../?.lua;" .. package.path +advtrains = {} +_G.advtrains = advtrains +local speed = require("speed") + +describe("Arithmetic functions on speed restrictions", function() + it("should work", function() + local a = math.random() + local b = math.random(20) + -- This test is basically a "typo check" + assert.is_true (speed.lessp(a, b)) + assert.is_false(speed.greaterp(a, b)) + assert.is_false(speed.not_lessp(a, b)) + assert.is_true (speed.not_greaterp(a, b)) + assert.is_false(speed.lessp(a, a)) + assert.is_false(speed.greaterp(a, a)) + assert.is_true (speed.equalp(a, a)) + assert.is_false(speed.not_equalp(a, a)) + assert.equal(b, speed.max(a, b)) + assert.equal(a, speed.min(a, b)) + end) + it("should handle -1", function() + assert.is_false(speed.lessp(-1, math.random())) + end) + it("should handle nil", function() + assert.is_false(speed.greaterp(nil, math.random())) + end) + it("should handle mixed nil and -1", function() + assert.is_true(speed.equalp(nil, -1)) + end) +end) + +describe("The speed restriction setter", function() + it("should set the signal aspect", function() + local t = {speed_restrictions_t = {x = 5, y = 9}} + local u = {speed_restrictions_t = {x = 7, y = 9}, speed_restriction = 7} + speed.merge_aspect(t, {main = 7, type = "x"}) + assert.same(u, t) + end) + it("should work with existing signal aspect tables", function() + local t = {speed_restrictions_t = {main = 5, foo = 3}} + local u = {speed_restrictions_t = {main = 7, foo = 3}, speed_restriction = 3} + speed.merge_aspect(t, {main = 7}) + assert.same(u, t) + end) + it("should work with distant signals", function() + local t = {speed_restrictions_t = {main = 5}} + local u = {speed_restrictions_t = {main = 5}, speed_restriction = 5} + speed.merge_aspect(t, {}) + assert.same(u, t) + end) + it("should create the restriction table if necessary", function() + local t = {speed_restriction = 5} + local u = {speed_restriction = 3, speed_restrictions_t = {main = 5, foo = 3}} + speed.merge_aspect(t, {main = 3, type = "foo"}) + assert.same(u, t) + end) + it("should also create the restriction table for trains without any speed limit", function() + local t = {} + local u = {speed_restrictions_t = {}} + speed.merge_aspect(t, {}) + assert.same(u, t) + end) + it("should set the speed restriction to nil if that is the case", function() + local t = {speed_restriction = math.random(20)} + local u = {speed_restrictions_t = {main = -1}} + speed.merge_aspect(t, {main = -1}) + assert.same(u, t) + end) +end) diff --git a/advtrains/speed.lua b/advtrains/speed.lua new file mode 100644 index 0000000..ec4f928 --- /dev/null +++ b/advtrains/speed.lua @@ -0,0 +1,88 @@ +-- auxiliary functions for the reworked speed restriction system + +local function s_lessp(a, b) + if not a or a == -1 then + return false + elseif not b or b == -1 then + return true + else + return a < b + end +end + +local function s_greaterp(a, b) + return s_lessp(b, a) +end + +local function s_not_lessp(a, b) + return not s_lessp(a, b) +end + +local function s_not_greaterp(a, b) + return not s_greaterp(a, b) +end + +local function s_equalp(a, b) + return (a or -1) == (b or -1) +end + +local function s_not_equalp(a, b) + return (a or -1) ~= (b or -1) +end + +local function s_max(a, b) + if s_lessp(a, b) then + return b + else + return a + end +end + +local function s_min(a, b) + if s_lessp(a, b) then + return a + else + return b + end +end + +local function get_speed_restriction_from_table (tbl) + local strictest = -1 + for _, v in pairs(tbl) do + strictest = s_min(strictest, v) + end + if strictest == -1 then + return nil + end + return strictest +end + +local function set_speed_restriction (tbl, rtype, rval) + if rval then + tbl[rtype or "main"] = rval + end + return tbl +end + +local function set_speed_restriction_for_train (train, rtype, rval) + local t = train.speed_restrictions_t or {main = train.speed_restriction} + train.speed_restrictions_t = set_speed_restriction(t, rtype, rval) + train.speed_restriction = get_speed_restriction_from_table(t) +end + +local function merge_speed_restriction_from_aspect_to_train (train, asp) + return set_speed_restriction_for_train(train, asp.type, asp.main) +end + +return { + lessp = s_lessp, + greaterp = s_greaterp, + not_lessp = s_not_lessp, + not_greaterp = s_not_greaterp, + equalp = s_equalp, + not_equalp = s_not_equalp, + max = s_max, + min = s_min, + set_restriction = set_speed_restriction_for_train, + merge_aspect = merge_speed_restriction_from_aspect_to_train, +} diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua index e7f2fd4..10af567 100644 --- a/advtrains/trainlogic.lua +++ b/advtrains/trainlogic.lua @@ -1168,6 +1168,7 @@ function advtrains.split_train_at_index(train, index) newtrain.line = train.line newtrain.routingcode = train.routingcode newtrain.speed_restriction = train.speed_restriction + newtrain.speed_restrictions_t = table.copy(train.speed_restrictions_t) newtrain.is_shunt = train.is_shunt newtrain.points_split = advtrains.merge_tables(train.points_split) newtrain.autocouple = train.autocouple @@ -1210,10 +1211,10 @@ function advtrains.invert_train(train_id) -- If interlocking present, check whether this train is in a section and then set as shunt move after reversion if advtrains.interlocking and train.il_sections and #train.il_sections > 0 then train.is_shunt = true - train.speed_restriction = advtrains.SHUNT_SPEED_MAX + advtrains.speed.set_restriction(train, "main", advtrains.SHUNT_SPEED_MAX) else train.is_shunt = false - train.speed_restriction = nil + advtrains.speed.set_restriction(train, "main", -1) end end -- cgit v1.2.3