Play the WikiHitler game - get from any Wikipedia article to Hitler's page by clicking links
Size
11.7 KB
Version
1.0.1
Created
Oct 22, 2025
Updated
1 day ago
1// ==UserScript==
2// @name WikiHitler Game
3// @description Play the WikiHitler game - get from any Wikipedia article to Hitler's page by clicking links
4// @version 1.0.1
5// @match https://*.en.wikipedia.org/*
6// @icon https://en.wikipedia.org/static/favicon/wikipedia.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 const HITLER_PAGE = 'Adolf_Hitler';
12 const GAME_STATE_KEY = 'wikihitler_game_state';
13
14 // Add styles for the game UI
15 TM_addStyle(`
16 #wikihitler-panel {
17 position: fixed;
18 top: 20px;
19 right: 20px;
20 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
21 color: white;
22 padding: 20px;
23 border-radius: 12px;
24 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
25 z-index: 10000;
26 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
27 min-width: 280px;
28 backdrop-filter: blur(10px);
29 }
30
31 #wikihitler-panel h2 {
32 margin: 0 0 15px 0;
33 font-size: 24px;
34 font-weight: bold;
35 text-align: center;
36 text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
37 }
38
39 #wikihitler-stats {
40 background: rgba(255, 255, 255, 0.2);
41 padding: 15px;
42 border-radius: 8px;
43 margin-bottom: 15px;
44 backdrop-filter: blur(5px);
45 }
46
47 #wikihitler-stats div {
48 margin: 8px 0;
49 font-size: 16px;
50 display: flex;
51 justify-content: space-between;
52 align-items: center;
53 }
54
55 #wikihitler-stats strong {
56 font-weight: 600;
57 }
58
59 #wikihitler-stats .stat-value {
60 background: rgba(255, 255, 255, 0.3);
61 padding: 4px 12px;
62 border-radius: 20px;
63 font-weight: bold;
64 font-size: 18px;
65 }
66
67 .wikihitler-btn {
68 width: 100%;
69 padding: 12px;
70 margin: 8px 0;
71 border: none;
72 border-radius: 8px;
73 font-size: 16px;
74 font-weight: 600;
75 cursor: pointer;
76 transition: all 0.3s ease;
77 text-transform: uppercase;
78 letter-spacing: 0.5px;
79 }
80
81 #wikihitler-start {
82 background: #10b981;
83 color: white;
84 }
85
86 #wikihitler-start:hover {
87 background: #059669;
88 transform: translateY(-2px);
89 box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);
90 }
91
92 #wikihitler-reset {
93 background: #ef4444;
94 color: white;
95 }
96
97 #wikihitler-reset:hover {
98 background: #dc2626;
99 transform: translateY(-2px);
100 box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4);
101 }
102
103 #wikihitler-random {
104 background: #f59e0b;
105 color: white;
106 }
107
108 #wikihitler-random:hover {
109 background: #d97706;
110 transform: translateY(-2px);
111 box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);
112 }
113
114 .wikihitler-success {
115 background: rgba(16, 185, 129, 0.3);
116 padding: 15px;
117 border-radius: 8px;
118 margin-bottom: 15px;
119 text-align: center;
120 font-size: 18px;
121 font-weight: bold;
122 animation: pulse 2s infinite;
123 }
124
125 @keyframes pulse {
126 0%, 100% { transform: scale(1); }
127 50% { transform: scale(1.05); }
128 }
129
130 .wikihitler-path {
131 background: rgba(255, 255, 255, 0.2);
132 padding: 10px;
133 border-radius: 8px;
134 margin-top: 10px;
135 max-height: 200px;
136 overflow-y: auto;
137 font-size: 12px;
138 }
139
140 .wikihitler-path-item {
141 padding: 5px;
142 margin: 3px 0;
143 background: rgba(255, 255, 255, 0.1);
144 border-radius: 4px;
145 word-break: break-word;
146 }
147 `);
148
149 async function getGameState() {
150 const state = await GM.getValue(GAME_STATE_KEY, null);
151 return state ? JSON.parse(state) : null;
152 }
153
154 async function saveGameState(state) {
155 await GM.setValue(GAME_STATE_KEY, JSON.stringify(state));
156 }
157
158 async function clearGameState() {
159 await GM.deleteValue(GAME_STATE_KEY);
160 }
161
162 function getCurrentPageTitle() {
163 const url = window.location.pathname;
164 const match = url.match(/\/wiki\/(.+)/);
165 return match ? decodeURIComponent(match[1]) : null;
166 }
167
168 function isHitlerPage() {
169 const currentPage = getCurrentPageTitle();
170 return currentPage === HITLER_PAGE;
171 }
172
173 async function startNewGame() {
174 const currentPage = getCurrentPageTitle();
175 if (!currentPage) {
176 console.error('Could not determine current page');
177 return;
178 }
179
180 const gameState = {
181 startPage: currentPage,
182 clicks: 0,
183 path: [currentPage],
184 active: true,
185 startTime: Date.now()
186 };
187
188 await saveGameState(gameState);
189 console.log('WikiHitler game started from:', currentPage);
190 updateUI();
191 }
192
193 async function trackClick() {
194 const gameState = await getGameState();
195 if (!gameState || !gameState.active) return;
196
197 const currentPage = getCurrentPageTitle();
198 if (!currentPage) return;
199
200 // Don't count if we're on the same page
201 if (gameState.path[gameState.path.length - 1] === currentPage) return;
202
203 gameState.clicks++;
204 gameState.path.push(currentPage);
205
206 // Check if we reached Hitler
207 if (isHitlerPage()) {
208 gameState.active = false;
209 gameState.endTime = Date.now();
210 gameState.won = true;
211 console.log('🎉 You reached Hitler in', gameState.clicks, 'clicks!');
212 }
213
214 await saveGameState(gameState);
215 updateUI();
216 }
217
218 async function resetGame() {
219 await clearGameState();
220 updateUI();
221 }
222
223 function goToRandomArticle() {
224 window.location.href = 'https://en.wikipedia.org/wiki/Special:Random';
225 }
226
227 async function updateUI() {
228 let panel = document.getElementById('wikihitler-panel');
229
230 if (!panel) {
231 panel = document.createElement('div');
232 panel.id = 'wikihitler-panel';
233 document.body.appendChild(panel);
234 }
235
236 const gameState = await getGameState();
237 const currentPage = getCurrentPageTitle();
238 const onHitlerPage = isHitlerPage();
239
240 let html = '<h2>🎯 WikiHitler</h2>';
241
242 if (gameState && gameState.active) {
243 html += '<div id="wikihitler-stats">';
244 html += `<div><strong>Clicks:</strong> <span class="stat-value">${gameState.clicks}</span></div>`;
245 html += `<div><strong>Start:</strong> <span style="font-size: 12px;">${gameState.startPage.replace(/_/g, ' ')}</span></div>`;
246 html += `<div><strong>Current:</strong> <span style="font-size: 12px;">${currentPage ? currentPage.replace(/_/g, ' ') : 'Unknown'}</span></div>`;
247 html += '</div>';
248
249 if (gameState.path.length > 1) {
250 html += '<div class="wikihitler-path">';
251 html += '<strong>Path:</strong>';
252 gameState.path.forEach((page, index) => {
253 html += `<div class="wikihitler-path-item">${index + 1}. ${page.replace(/_/g, ' ')}</div>`;
254 });
255 html += '</div>';
256 }
257
258 html += '<button id="wikihitler-reset" class="wikihitler-btn">Reset Game</button>';
259 } else if (gameState && gameState.won) {
260 const timeTaken = Math.round((gameState.endTime - gameState.startTime) / 1000);
261 html += '<div class="wikihitler-success">🎉 YOU WON! 🎉</div>';
262 html += '<div id="wikihitler-stats">';
263 html += `<div><strong>Clicks:</strong> <span class="stat-value">${gameState.clicks}</span></div>`;
264 html += `<div><strong>Time:</strong> <span class="stat-value">${timeTaken}s</span></div>`;
265 html += '</div>';
266
267 if (gameState.path.length > 0) {
268 html += '<div class="wikihitler-path">';
269 html += '<strong>Winning Path:</strong>';
270 gameState.path.forEach((page, index) => {
271 html += `<div class="wikihitler-path-item">${index + 1}. ${page.replace(/_/g, ' ')}</div>`;
272 });
273 html += '</div>';
274 }
275
276 html += '<button id="wikihitler-random" class="wikihitler-btn">New Game (Random)</button>';
277 html += '<button id="wikihitler-reset" class="wikihitler-btn">Reset</button>';
278 } else {
279 html += '<div id="wikihitler-stats">';
280 html += '<div style="text-align: center; margin-bottom: 10px;">Get to Hitler\'s page by clicking Wikipedia links!</div>';
281 html += '</div>';
282
283 if (onHitlerPage) {
284 html += '<div style="background: rgba(239, 68, 68, 0.3); padding: 10px; border-radius: 8px; margin-bottom: 10px; text-align: center;">You\'re already on Hitler\'s page! Start from a different article.</div>';
285 html += '<button id="wikihitler-random" class="wikihitler-btn">Random Article</button>';
286 } else {
287 html += '<button id="wikihitler-start" class="wikihitler-btn">Start Game</button>';
288 html += '<button id="wikihitler-random" class="wikihitler-btn">Random Article</button>';
289 }
290 }
291
292 panel.innerHTML = html;
293
294 // Attach event listeners
295 const startBtn = document.getElementById('wikihitler-start');
296 if (startBtn) {
297 startBtn.addEventListener('click', startNewGame);
298 }
299
300 const resetBtn = document.getElementById('wikihitler-reset');
301 if (resetBtn) {
302 resetBtn.addEventListener('click', resetGame);
303 }
304
305 const randomBtn = document.getElementById('wikihitler-random');
306 if (randomBtn) {
307 randomBtn.addEventListener('click', goToRandomArticle);
308 }
309 }
310
311 // Intercept clicks on Wikipedia article links
312 function setupLinkTracking() {
313 document.addEventListener('click', async (e) => {
314 const link = e.target.closest('a[href^="/wiki/"]');
315 if (!link) return;
316
317 const href = link.getAttribute('href');
318
319 // Ignore special pages, files, and non-article links
320 if (href.includes(':') || href.includes('#')) return;
321
322 const gameState = await getGameState();
323 if (gameState && gameState.active) {
324 // Track the click after a short delay to let the page load
325 setTimeout(trackClick, 1000);
326 }
327 });
328 }
329
330 // Initialize
331 async function init() {
332 console.log('WikiHitler game loaded!');
333
334 // Check if we're on a valid Wikipedia article page
335 const currentPage = getCurrentPageTitle();
336 if (!currentPage || currentPage.includes(':')) {
337 console.log('Not on a valid Wikipedia article page');
338 return;
339 }
340
341 // Track page load if game is active
342 await trackClick();
343
344 // Setup UI and link tracking
345 await updateUI();
346 setupLinkTracking();
347 }
348
349 // Wait for page to be ready
350 if (document.readyState === 'loading') {
351 document.addEventListener('DOMContentLoaded', init);
352 } else {
353 init();
354 }
355})();