You are given roller coaster descriptions and a rules dictionary. Each description is still a string in the format '<CoasterType> <MaxSpeed> <BumpsPerSecond> <LiftType>'. The rules dictionary is keyed by coaster type. Each rule contains 'scale' and 'comfort_model', plus model-specific fields. Supported comfort models are: 'inverse_bumps' -> min(1.0, base / bumps), 'inverse_speed' -> min(1.0, base / speed), 'inverse_bumps_plus_lift_bonus' -> min(1.0, base / bumps) + lift_bonus.get(lift_type, 0.0), and 'constant' -> value. For each coaster, compute score = scale * comfort * speed and return formatted strings 'Overall: <score>' rounded to one decimal place. The solution should be data-driven so new coaster types or changed parameters can be handled by changing only the rules input, not the core processing loop.
Examples
Input: (['Wooden 4 2 Chain', 'Steel 20 0 Cable', 'Suspended 2 0.5 Cable'], {'Wooden': {'scale': 1.0, 'comfort_model': 'inverse_bumps', 'base': 1.0}, 'Steel': {'scale': 2.0, 'comfort_model': 'inverse_speed', 'base': 5.0}, 'Suspended': {'scale': 0.5, 'comfort_model': 'inverse_bumps_plus_lift_bonus', 'base': 1.0, 'lift_bonus': {'Cable': 0.5, 'Launched': 0.1}}})
Expected Output: ['Overall: 2.0', 'Overall: 10.0', 'Overall: 1.5']
Explanation: These rules reproduce the original three coaster types using a data-driven configuration.
Input: (['Hybrid 12 8 Magnetic'], {'Hybrid': {'scale': 1.5, 'comfort_model': 'constant', 'value': 0.8}})
Expected Output: ['Overall: 14.4']
Explanation: A brand new type is added only by changing the rules data: 1.5 * 0.8 * 12 = 14.4.
Input: (['Wooden 10 4 Chain'], {'Wooden': {'scale': 2.0, 'comfort_model': 'inverse_bumps', 'base': 2.0}})
Expected Output: ['Overall: 10.0']
Explanation: Changing the scale and base values in the rule changes the score without any change to the loop logic.
Input: ([], {'Wooden': {'scale': 1.0, 'comfort_model': 'inverse_bumps', 'base': 1.0}})
Expected Output: []
Explanation: Edge case: no coasters means no output strings.
Input: (['Suspended 6 2 Chain'], {'Suspended': {'scale': 0.5, 'comfort_model': 'inverse_bumps_plus_lift_bonus', 'base': 1.0, 'lift_bonus': {'Cable': 0.5, 'Launched': 0.1}}})
Expected Output: ['Overall: 1.5']
Explanation: Chain is not present in lift_bonus, so the bonus defaults to 0.0.