Jump to content

Module:RiskLadder

From RiskiPedia

Template:Documentation subpage

Description

This module provides a "risk context" for small probabilities. It is designed to be called by the {{RiskLadder}} template.

When given a fractional probability, it finds a "risk equivalent" from a predefined list and displays it to the user. This helps make abstract, small numbers (like "1-in-100,000") feel more tangible by comparing them to a more familiar risk (e.g., "your risk of a fatal incident on a single skydive").

The module logic: 1. Converts the probability (e.g., `0.00001`) into its "1-in-X" form (e.g., `100,000`). 2. Searches Module:RiskLadder/Data to find the comparison risk with the closest "X" value. 3. Randomly selects one comparison from that risk's "pool" (if there are multiple). 4. Displays the comparison in a formatted box.

Usage

Via Template (Recommended)

The primary way to use this module is through the {{RiskLadder}} template.

{{RiskLadder|PROBABILITY|SEED}}
  • `PROBABILITY` (required): The fractional probability. E.g., `0.00005` or `5.0E-5`.
  • `SEED` (optional): A number. Use this if you have multiple `RiskLadder` calls on the same page and want them to show different comparisons.

Via #invoke (for testing)

You can also call the module directly from wikitext.

{{#invoke:RiskLadder|main
  | prob = PROBABILITY
  | seed = SEED
}}

Examples

Wikitext Result
{{#invoke:RiskLadder|main|prob=0.00005|debug=1}} (1-in-20,000) Template:RiskLadder
{{#invoke:RiskLadder|main|prob=0.00005|seed=1}} (1-in-20,000, seed 1) Template:RiskLadder
{{#invoke:RiskLadder|main|0.00005|2}} (1-in-20,000, seed 2) Template:RiskLadder
{{RiskLadder|0.0000011}} (1-in-909,091) Template:RiskLadder
{{RiskLadder|0.005}} (1-in-200) Template:RiskLadder
{{RiskLadder|0.05}} (Out of range) Template:RiskLadder
{{RiskLadder|}} (No probability) Template:RiskLadder


See Also


local p = {}

-- Load the risk data from the sub-module 
local riskData = require('Module:RiskLadder/Data')

-- Helper function to find the closest available risk pool
-- Returns the pool AND the key (the "X" value) of that pool
local function findClosestPool(x)
	local bestKey = nil
	local minDiff = math.huge
	
	for key in pairs(riskData) do
		local diff = math.abs(key - x)
		if diff < minDiff then
			minDiff = diff
			bestKey = key
		end
	end
	
	if bestKey then
		return riskData[bestKey], bestKey
	else
		return nil, nil -- No keys found in data
	end
end

-- Main function called by {{#invoke:RiskLadder|main}}
function p.main(frame)
	-- Get arguments
	local args = frame.args

	local prob = tonumber(args.prob)
	local userSeed = tonumber(args.seed) or 0
	
	-- === 1. VALIDATE INPUT ===
	if not prob then
		return '<span class="error" style="color: red; font-weight: bold;">RiskLadder Error:</span> No probability provided.'
	end
	
	if prob > 0.01 or prob < 0.000001 then
		return '<span class="error" style="color: red; font-weight: bold;">RiskLadder Error:</span> Probability is outside the template\'s display range (1-in-100 to 1-in-1,000,000).'
	end

	-- === 2. FIND THE BEST BUCKET ===
	-- Calculate our "1-in-X" value
	local x = 1 / prob
	
	-- Find the closest matching pool and its key
	local pool, bestKey = findClosestPool(x)

	if not pool or #pool == 0 then
		return "" -- No comparison found, show nothing
	end

	-- === 3. PICK A COMPARISON ===
	local pageId = mw.title.getCurrentTitle().id or 0
	local seed = pageId + userSeed
	local poolSize = #pool
	local itemIndex = (seed % poolSize) + 1
	local chosenItem = pool[itemIndex]
	
	-- === 4. DETERMINE COMPARISON WORDING ===
	-- Decide whether to say "less than", "more than", or "roughly the same as"
	-- We use a 20% threshold to decide.
	local prefix = ""
	local ratio = x / bestKey
	
	if ratio > 1.2 then
		-- e.g., Our risk is 1-in-10,000, closest is 1-in-8,000.
		-- Our risk is SMALLER, so it's "less than".
		prefix = "less than "
	elseif ratio < 0.8 then
		-- e.g., Our risk is 1-in-6,000, closest is 1-in-8,000.
		-- Our risk is LARGER, so it's "more than ".
		prefix = "more than "
	else
		-- e.g., Our risk is 1-in-8,100, closest is 1-in-8,000.
		prefix = "roughly the same as "
	end

	-- === 5. BUILD THE OUTPUT ===
	-- Return a single, simple span
	return string.format(
		'<span class="riskcomparison">%s%s.</span>',
		prefix,
		chosenItem
	)
end

return p