mihail / game.txt

Last active 3 hours ago

Like 0

mihail revised this gist 3 hours ago Β· 04c3476

1 file changed, 142 insertions

game.txt (file created)
@@ -0,0 +1,142 @@
1 + 1. Helpers (configuration.yaml, or create them in the UI)
2 +
3 + input_button:
4 + station_game_start:
5 + name: Start station game
6 + icon: mdi:bus-clock
7 +
8 + # One dropdown per player. Options = "-" (no pick) + station names.
9 + # Station names must match the keys in the automation's `stations` map.
10 + input_select:
11 + station_game_alice:
12 + name: Alice's station
13 + icon: mdi:account
14 + options: ["-", "Stratford", "Hackney Wick", "Canning Town", "Bow Road"]
15 + station_game_bob:
16 + name: Bob's station
17 + icon: mdi:account
18 + options: ["-", "Stratford", "Hackney Wick", "Canning Town", "Bow Road"]
19 + station_game_carol:
20 + name: Carol's station
21 + icon: mdi:account
22 + options: ["-", "Stratford", "Hackney Wick", "Canning Town", "Bow Road"]
23 +
24 + 2. Automation
25 +
26 + alias: Station arrival game
27 + description: Everyone picks a station; soonest next arrival wins.
28 + mode: single
29 + triggers:
30 + - trigger: state
31 + entity_id: input_button.station_game_start
32 + not_from: [unavailable, unknown]
33 + variables:
34 + pick_timeout: 60 # seconds players get to choose
35 + departures_attr: departures # attribute holding the arrivals list
36 + notify_action: notify.notify
37 + stations:
38 + Stratford: sensor.stratford_departures
39 + Hackney Wick: sensor.hackney_wick_departures
40 + Canning Town: sensor.canning_town_departures
41 + Bow Road: sensor.bow_road_departures
42 + players:
43 + Alice: input_select.station_game_alice
44 + Bob: input_select.station_game_bob
45 + Carol: input_select.station_game_carol
46 + actions:
47 + # Reset everyone's pick
48 + - action: input_select.select_option
49 + target:
50 + entity_id: "{{ players.values() | list }}"
51 + data:
52 + option: "-"
53 +
54 + - action: "{{ notify_action }}"
55 + data:
56 + title: "🚌 Station game!"
57 + message: >
58 + Pick your station within {{ pick_timeout }}s.
59 + Soonest arrival wins. Options: {{ stations.keys() | join(', ') }}
60 +
61 + # Wait until everyone has picked, or time runs out
62 + - wait_template: >
63 + {{ players.values() | map('states') | select('eq', '-') | list | count == 0 }}
64 + timeout:
65 + seconds: "{{ pick_timeout }}"
66 + continue_on_timeout: true
67 +
68 + # Find each player's soonest future arrival
69 + - variables:
70 + results: >
71 + {% set ns = namespace(r=[]) %}
72 + {% for player, sel in players.items() %}
73 + {% set station = states(sel) %}
74 + {% set sensor = stations.get(station) %}
75 + {% if sensor %}
76 + {% set best = namespace(t=none, d=none) %}
77 + {% for d in state_attr(sensor, departures_attr) or [] %}
78 + {% set t = as_datetime(d.expected) if d.expected else none %}
79 + {% if t and t > now() and (best.t is none or t < best.t) %}
80 + {% set best.t = t %}
81 + {% set best.d = d %}
82 + {% endif %}
83 + {% endfor %}
84 + {% if best.t is not none %}
85 + {% set ns.r = ns.r + [{
86 + 'player': player,
87 + 'station': station,
88 + 'secs': (best.t - now()).total_seconds() | int,
89 + 'line': best.d.line.designation if best.d.line is mapping else '?',
90 + 'mode': best.d.line.transport_mode if best.d.line is mapping else '',
91 + 'dest': best.d.destination
92 + }] %}
93 + {% endif %}
94 + {% endif %}
95 + {% endfor %}
96 + {{ ns.r | sort(attribute='secs') }}
97 + no_pick: >
98 + {{ players.items() | selectattr('1', 'is_state', '-') | map(attribute='0') | list }}
99 + winners: >
100 + {% if results | count > 0 %}
101 + {{ results | selectattr('secs', 'eq', results[0].secs) | map(attribute='player') | list }}
102 + {% else %}[]{% endif %}
103 +
104 + - choose:
105 + - conditions: "{{ winners | count > 0 }}"
106 + sequence:
107 + - action: "{{ notify_action }}"
108 + data:
109 + title: >
110 + πŸ† {{ winners | join(' & ') }} win{{ 's' if winners | count == 1 }}!
111 + message: >
112 + {% for r in results -%}
113 + {{ loop.index }}. {{ r.player }} – {{ r.station }}:
114 + {{ r.mode | lower }} {{ r.line }} β†’ {{ r.dest }}
115 + in {{ r.secs // 60 }}m {{ '%02d' % (r.secs % 60) }}s
116 + {% endfor -%}
117 + {% if no_pick %}Didn't pick: {{ no_pick | join(', ') }}{% endif %}
118 + default:
119 + - action: "{{ notify_action }}"
120 + data:
121 + title: "🚌 Station game"
122 + message: "No valid picks or no upcoming arrivals. Nobody wins."
123 +
124 + 3. Dashboard card (optional)
125 +
126 + type: entities
127 + title: Station game
128 + entities:
129 + - input_button.station_game_start
130 + - input_select.station_game_alice
131 + - input_select.station_game_bob
132 + - input_select.station_game_carol
133 +
134 + How it works
135 +
136 + - Start: press the button. Everyone's pick resets to - and a notification goes out.
137 + - Picking: each player sets their own dropdown. The game ends early once all players have picked, otherwise after 60s. Anyone who didn't
138 + pick is left out and named in the results.
139 + - Winner: for each pick, the automation takes the earliest expected time that is still in the future (it skips past arrivals). The lowest
140 + wait wins.
141 + - Ties: if two players pick the same station or get identical times, they share the win.
142 + - Results: the notification shows the full ranking with mode, line, destination and countdown.