Demonstrates grid cell highlighting and "mines" marking on a demo grid for learning Tampermonkey scripting. Safe for testing on your own pages.
// ==UserScript==
// @name Liljohnjohn predictor
// @namespace http://tampermonkey.net/
// @version v5.5.0
// @description Demonstrates grid cell highlighting and "mines" marking on a demo grid for learning Tampermonkey scripting. Safe for testing on your own pages.
// @author You
// @match https://bloxflip.com/mines*
// @match https://bloxflip.com/mines*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Configuration
const PANEL_ID = 'tmpt_demo_panel';
const GRID_ID = 'tmpt_demo_grid';
const LS_KEY = 'tmpt_demo_grid_state_v1';
const DEMO_SIZE = { rows: 5, cols: 5 }; // adjustable demo grid size
// Helper: inject minimal CSS for the demo UI
function injectCSS() {
if (document.getElementById('tmpt_demo_style')) return;
const style = document.createElement('style');
style.id = 'tmpt_demo_style';
style.textContent = `
#${PANEL_ID} {
position: fixed;
bottom: 12px;
right: 12px;
background: rgba(0,0,0,0.85);
color: #fff;
padding: 12px;
border-radius: 8px;
font-family: Arial, sans-serif;
z-index: 9999;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
#${PANEL_ID} h3 { margin: 0 0 6px 0; font-size: 14px; }
#${PANEL_ID} button {
margin: 4px 2px;
padding: 6px 10px;
font-size: 12px;
}
#${GRID_ID} {
display: grid;
gap: 6px;
position: fixed;
bottom: 100px;
right: 12px;
padding: 6px;
background: rgba(255,255,255,0.95);
border: 1px solid #ccc;
border-radius: 8px;
z-index: 9998;
box-shadow: 0 6px 16px rgba(0,0,0,0.15);
}
#${GRID_ID} .cell {
width: 40px;
height: 40px;
background: #e0e0e0;
border: 1px solid #bbb;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
font-size: 12px;
border-radius: 4px;
}
#${GRID_ID} .cell.marked { outline: 3px solid orange; background: #ffd8a8; }
#${GRID_ID} .cell.mine { background: #ff4d4d; border-color: #d00; }
#${GRID_ID} .cell.revealed { background: #ffd6d6; }
`;
document.head.appendChild(style);
}
// Create a demo grid if none exists on the page
function ensureDemoGrid() {
let grid = document.querySelector('#' + GRID_ID);
let cells = [];
if (grid) {
cells = Array.from(grid.querySelectorAll('.cell'));
return { grid, cells };
}
// Create a small demo grid
grid = document.createElement('div');
grid.id = GRID_ID;
grid.style.gridTemplateColumns = `repeat(${DEMO_SIZE.cols}, 40px)`;
grid.style.gridTemplateRows = `repeat(${DEMO_SIZE.rows}, 40px)`;
// Build cells
for (let r = 0; r < DEMO_SIZE.rows; r++) {
for (let c = 0; c < DEMO_SIZE.cols; c++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = r;
cell.dataset.col = c;
cell.title = `R${r+1}C${c+1}`;
grid.appendChild(cell);
cells.push(cell);
// Click: toggle marked (simulated mine)
cell.addEventListener('click', () => {
cell.classList.toggle('marked');
saveState();
});
}
}
document.body.appendChild(grid);
return { grid, cells };
}
// Panel with controls
function createPanel() {
const panel = document.createElement('div');
panel.id = PANEL_ID;
panel.innerHTML = `
<h3>Grid Mine Demo</h3>
<button id="tmpt_toggle_grid">Enable/Reset Demo Grid</button>
<button id="tmpt_rand_mines">Randomize Mines</button>
<button id="tmpt_reveal_mines">Reveal Mines</button>
<button id="tmpt_clear_marks">Clear All Marks</button>
<div style="font-size:12px; opacity:0.9; margin-top:6px;">
This is a safe learning tool. Use on pages you own or test locally.
</div>
`;
document.body.appendChild(panel);
document.getElementById('tmpt_toggle_grid').addEventListener('click', () => {
// Ensure grid exists and clear previous
ensureDemoGrid();
// Clear any existing mines/marks for a fresh demo
clearMines();
saveState();
});
document.getElementById('tmpt_rand_mines').addEventListener('click', () => {
const { cells } = ensureDemoGrid();
if (!cells.length) return;
// Reset mines
cells.forEach(c => c.classList.remove('mine'));
// Randomize a small number of mines (e.g., ~20%)
const k = Math.max(1, Math.floor(cells.length * 0.2));
const indices = new Set();
while (indices.size < k) {
indices.add(Math.floor(Math.random() * cells.length));
}
indices.forEach(i => cells[i].classList.add('mine'));
saveState();
});
document.getElementById('tmpt_reveal_mines').addEventListener('click', () => {
// Reveal by adding a subtle class to all cells that have mine
const { cells } = ensureDemoGrid();
cells.forEach(cell => {
if (cell.classList.contains('mine')) {
cell.classList.add('revealed');
}
});
});
document.getElementById('tmpt_clear_marks').addEventListener('click', () => {
clearMines();
// Also remove marked class from cells
const { cells } = ensureDemoGrid();
cells.forEach(c => c.classList.remove('marked', 'revealed'));
saveState();
});
}
// State persistence
function saveState() {
const gridObj = document.querySelector('#' + GRID_ID);
if (!gridObj) return;
const cells = Array.from(gridObj.querySelectorAll('.cell'));
const state = cells.map((cell) => ({
r: cell.dataset.row,
c: cell.dataset.col,
marked: cell.classList.contains('marked'),
mine: cell.classList.contains('mine'),
revealed: cell.classList.contains('revealed')
}));
localStorage.setItem(LS_KEY, JSON.stringify(state));
}
function loadState() {
const raw = localStorage.getItem(LS_KEY);
if (!raw) return;
try {
const state = JSON.parse(raw);
const grid = document.querySelector('#' + GRID_ID);
if (!grid) return;
state.forEach((s) => {
const sel = grid.querySelector(`.cell[data-row="${s.r}"][data-col="${s.c}"]`);
if (sel) {
if (s.marked) sel.classList.add('marked');
if (s.mine) sel.classList.add('mine');
if (s.revealed) sel.classList.add('revealed');
}
});
} catch (e) {
console.warn('Failed to load demo grid state', e);
}
}
function clearMines() {
const grid = document.querySelector('#' + GRID_ID);
if (!grid) return;
grid.querySelectorAll('.cell').forEach((cell) => {
cell.classList.remove('marked', 'mine', 'revealed');
});
}
// Init
function init() {
injectCSS();
createPanel();
// Try to ensure a demo grid exists (or rely on the panel to create one)
ensureDemoGrid();
loadState();
}
// Run after DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();