XTaylorSpenceX

Palindrome Palace Builder

Oct 9th, 2025
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 16.46 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Palindrome Palace Builder</title>
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. box-sizing: border-box;
  12. }
  13. @keyframes glow {
  14. 0%, 100% { filter: drop-shadow(0 0 20px rgba(255, 0, 255, 0.5)); }
  15. 50% { filter: drop-shadow(0 0 40px rgba(0, 255, 255, 0.8)); }
  16. }
  17. @keyframes shake {
  18. 0%, 100% { transform: translateX(0); }
  19. 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
  20. 20%, 40%, 60%, 80% { transform: translateX(5px); }
  21. }
  22. @keyframes collapse {
  23. 0% { transform: translateY(0) rotate(0deg); opacity: 1; }
  24. 100% { transform: translateY(500px) rotate(720deg); opacity: 0; }
  25. }
  26. @keyframes float {
  27. 0%, 100% { transform: translateY(0); }
  28. 50% { transform: translateY(-10px); }
  29. }
  30. body {
  31. min-height: 100vh;
  32. background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #c471f5 75%, #667eea 100%);
  33. background-size: 400% 400%;
  34. animation: gradient 15s ease infinite;
  35. font-family: 'Courier New', monospace;
  36. display: flex;
  37. flex-direction: column;
  38. align-items: center;
  39. overflow-x: hidden;
  40. position: relative;
  41. }
  42. @keyframes gradient {
  43. 0%, 100% { background-position: 0% 50%; }
  44. 50% { background-position: 100% 50%; }
  45. }
  46. #stars {
  47. position: fixed;
  48. width: 100%;
  49. height: 100%;
  50. top: 0;
  51. left: 0;
  52. pointer-events: none;
  53. z-index: 0;
  54. }
  55. .star {
  56. position: absolute;
  57. width: 2px;
  58. height: 2px;
  59. background: white;
  60. border-radius: 50%;
  61. animation: twinkle 3s infinite;
  62. }
  63. @keyframes twinkle {
  64. 0%, 100% { opacity: 0; }
  65. 50% { opacity: 1; }
  66. }
  67. #gameContainer {
  68. width: 100%;
  69. max-width: 1200px;
  70. padding: 20px;
  71. position: relative;
  72. z-index: 1;
  73. }
  74. #header {
  75. text-align: center;
  76. color: white;
  77. margin-bottom: 30px;
  78. animation: glow 3s infinite;
  79. }
  80. h1 {
  81. font-size: 3em;
  82. text-shadow: 0 0 30px rgba(255, 255, 255, 0.5);
  83. margin-bottom: 10px;
  84. background: linear-gradient(45deg, #fff, #ff00ff, #00ffff, #fff);
  85. background-size: 200% 200%;
  86. -webkit-background-clip: text;
  87. -webkit-text-fill-color: transparent;
  88. animation: gradient 3s ease infinite;
  89. }
  90. #stats {
  91. display: flex;
  92. justify-content: center;
  93. gap: 30px;
  94. margin-bottom: 20px;
  95. flex-wrap: wrap;
  96. }
  97. .stat {
  98. background: rgba(255, 255, 255, 0.1);
  99. backdrop-filter: blur(10px);
  100. border: 2px solid rgba(255, 255, 255, 0.3);
  101. border-radius: 20px;
  102. padding: 15px 25px;
  103. color: white;
  104. font-size: 1.1em;
  105. text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
  106. }
  107. .stat span {
  108. font-weight: bold;
  109. color: #00ffff;
  110. text-shadow: 0 0 15px #00ffff;
  111. }
  112. #inputArea {
  113. display: flex;
  114. gap: 15px;
  115. margin-bottom: 30px;
  116. justify-content: center;
  117. flex-wrap: wrap;
  118. }
  119. #palindromeInput {
  120. padding: 15px 25px;
  121. font-size: 1.2em;
  122. border: 3px solid rgba(255, 255, 255, 0.3);
  123. border-radius: 50px;
  124. background: rgba(0, 0, 0, 0.3);
  125. backdrop-filter: blur(10px);
  126. color: white;
  127. width: 400px;
  128. max-width: 90%;
  129. text-align: center;
  130. transition: all 0.3s;
  131. }
  132. #palindromeInput:focus {
  133. outline: none;
  134. border-color: #00ffff;
  135. box-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
  136. }
  137. #palindromeInput::placeholder {
  138. color: rgba(255, 255, 255, 0.5);
  139. }
  140. button {
  141. padding: 15px 35px;
  142. font-size: 1.1em;
  143. border: none;
  144. border-radius: 50px;
  145. background: linear-gradient(45deg, #ff00ff, #00ffff);
  146. color: white;
  147. font-weight: bold;
  148. cursor: pointer;
  149. transition: all 0.3s;
  150. text-transform: uppercase;
  151. letter-spacing: 2px;
  152. position: relative;
  153. overflow: hidden;
  154. }
  155. button:before {
  156. content: '';
  157. position: absolute;
  158. top: 50%;
  159. left: 50%;
  160. width: 0;
  161. height: 0;
  162. border-radius: 50%;
  163. background: rgba(255, 255, 255, 0.5);
  164. transform: translate(-50%, -50%);
  165. transition: width 0.5s, height 0.5s;
  166. }
  167. button:hover:before {
  168. width: 300px;
  169. height: 300px;
  170. }
  171. button:hover {
  172. transform: translateY(-3px);
  173. box-shadow: 0 10px 30px rgba(0, 255, 255, 0.5);
  174. }
  175. button:disabled {
  176. opacity: 0.5;
  177. cursor: not-allowed;
  178. }
  179. #palace {
  180. min-height: 400px;
  181. display: flex;
  182. flex-direction: column;
  183. align-items: center;
  184. position: relative;
  185. padding: 20px;
  186. margin-top: 30px;
  187. }
  188. .floor {
  189. display: flex;
  190. justify-content: center;
  191. width: 100%;
  192. margin-bottom: 5px;
  193. position: relative;
  194. }
  195. .beam {
  196. padding: 15px 25px;
  197. margin: 0 5px;
  198. background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(200, 200, 255, 0.9));
  199. border: 2px solid rgba(255, 255, 255, 0.8);
  200. border-radius: 10px;
  201. font-weight: bold;
  202. font-size: 1.1em;
  203. color: #4a0080;
  204. box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
  205. transition: all 0.3s;
  206. cursor: pointer;
  207. position: relative;
  208. animation: float 3s ease-in-out infinite;
  209. animation-delay: calc(var(--beam-index) * 0.1s);
  210. }
  211. .beam:hover {
  212. transform: scale(1.05);
  213. box-shadow: 0 8px 30px rgba(255, 0, 255, 0.5);
  214. background: linear-gradient(135deg, rgba(255, 255, 255, 1), rgba(255, 200, 255, 1));
  215. }
  216. .beam.strong {
  217. background: linear-gradient(135deg, #ffd700, #ffed4e);
  218. border-color: #ffd700;
  219. box-shadow: 0 5px 30px rgba(255, 215, 0, 0.5);
  220. }
  221. .beam.medium {
  222. background: linear-gradient(135deg, #c0c0c0, #e8e8e8);
  223. border-color: #c0c0c0;
  224. }
  225. .beam.weak {
  226. background: linear-gradient(135deg, #cd7f32, #d4a574);
  227. border-color: #cd7f32;
  228. opacity: 0.9;
  229. }
  230. .beam.shaking {
  231. animation: shake 0.5s;
  232. }
  233. .beam.collapsing {
  234. animation: collapse 1s forwards;
  235. }
  236. .stability-indicator {
  237. position: absolute;
  238. top: -25px;
  239. right: -10px;
  240. background: rgba(0, 0, 0, 0.7);
  241. color: white;
  242. padding: 5px 10px;
  243. border-radius: 15px;
  244. font-size: 0.9em;
  245. font-weight: normal;
  246. }
  247. #foundation {
  248. width: 80%;
  249. max-width: 600px;
  250. height: 30px;
  251. background: linear-gradient(90deg, #8b7355, #a0826d);
  252. border: 3px solid #654321;
  253. border-radius: 10px;
  254. margin-top: 20px;
  255. box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  256. }
  257. #message {
  258. position: fixed;
  259. top: 50%;
  260. left: 50%;
  261. transform: translate(-50%, -50%);
  262. background: rgba(0, 0, 0, 0.9);
  263. color: white;
  264. padding: 30px 50px;
  265. border-radius: 20px;
  266. border: 3px solid;
  267. font-size: 1.5em;
  268. display: none;
  269. text-align: center;
  270. z-index: 1000;
  271. animation: glow 2s infinite;
  272. }
  273. #message.success {
  274. border-color: #00ff00;
  275. box-shadow: 0 0 50px rgba(0, 255, 0, 0.5);
  276. }
  277. #message.error {
  278. border-color: #ff0000;
  279. box-shadow: 0 0 50px rgba(255, 0, 0, 0.5);
  280. }
  281. #message.warning {
  282. border-color: #ffff00;
  283. box-shadow: 0 0 50px rgba(255, 255, 0, 0.5);
  284. }
  285. .tooltip {
  286. position: absolute;
  287. bottom: 100%;
  288. left: 50%;
  289. transform: translateX(-50%);
  290. background: rgba(0, 0, 0, 0.9);
  291. color: #00ffff;
  292. padding: 8px 15px;
  293. border-radius: 10px;
  294. font-size: 0.9em;
  295. white-space: nowrap;
  296. opacity: 0;
  297. pointer-events: none;
  298. transition: opacity 0.3s;
  299. z-index: 100;
  300. }
  301. .beam:hover .tooltip {
  302. opacity: 1;
  303. }
  304. </style>
  305. </head>
  306. <body>
  307. <div id="stars"></div>
  308. <div id="gameContainer">
  309. <div id="header">
  310. <h1>✨ Palindrome Palace Builder ✨</h1>
  311. <p style="color: #fff; font-size: 1.2em; margin-top: 10px;">Stack symmetric phrases to build your mystical tower!</p>
  312. </div>
  313. <div id="stats">
  314. <div class="stat">Height: <span id="height">0</span> floors</div>
  315. <div class="stat">Stability: <span id="stability">100</span>%</div>
  316. <div class="stat">Score: <span id="score">0</span></div>
  317. <div class="stat">Disaster Risk: <span id="disasterRisk">Low</span></div>
  318. </div>
  319. <div id="inputArea">
  320. <input type="text" id="palindromeInput" placeholder="Enter a word (e.g., 'racecar' or any noun/adverb!)" />
  321. <button id="addBeam">Add Beam</button>
  322. <button id="testDisaster">Test Disaster</button>
  323. </div>
  324. <div id="palace">
  325. <div id="foundation"></div>
  326. </div>
  327. </div>
  328. <div id="message"></div>
  329. <script>
  330. class PalindromePalace {
  331. constructor() {
  332. this.beams = [];
  333. this.score = 0;
  334. this.height = 0;
  335. this.stability = 100;
  336. this.disasterEffects = {
  337. 'Earthquake': { resistant: ['adverb'], prone: ['verb'] },
  338. 'Tornado': { resistant: ['palindrome'], prone: ['pronoun', 'misspelled'] },
  339. 'Tsunami': { resistant: ['verb'], prone: ['noun'] },
  340. 'Volcano': { resistant: ['noun'], prone: ['adverb'] },
  341. 'Meteor': { resistant: ['misspelled'], prone: ['palindrome'] },
  342. 'Flood': { resistant: ['pronoun'], prone: ['verb'] }
  343. };
  344. this.autoDisasterTimer = null;
  345. this.init();
  346. }
  347. init() {
  348. this.createStars();
  349. this.setupEventListeners();
  350. this.updateDisplay();
  351. this.scheduleNextDisaster();
  352. }
  353. createStars() {
  354. const starsContainer = document.getElementById('stars');
  355. for (let i = 0; i < 100; i++) {
  356. const star = document.createElement('div');
  357. star.className = 'star';
  358. star.style.left = Math.random() * 100 + '%';
  359. star.style.top = Math.random() * 100 + '%';
  360. star.style.animationDelay = Math.random() * 3 + 's';
  361. starsContainer.appendChild(star);
  362. }
  363. }
  364. setupEventListeners() {
  365. document.getElementById('addBeam').addEventListener('click', () => this.addBeam());
  366. document.getElementById('testDisaster').addEventListener('click', () => this.triggerRandomDisaster());
  367. document.getElementById('palindromeInput').addEventListener('keypress', (e) => {
  368. if (e.key === 'Enter') this.addBeam();
  369. });
  370. }
  371. isPalindrome(str) {
  372. const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
  373. return cleaned === cleaned.split('').reverse().join('');
  374. }
  375. getWordType(word) {
  376. const cleaned = word.toLowerCase().replace(/[^a-z0-9]/g, '');
  377. if (this.isPalindrome(word)) return 'palindrome';
  378. const pronouns = ['i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her', 'us', 'them'];
  379. if (pronouns.includes(cleaned)) return 'pronoun';
  380. if (word.toLowerCase().endsWith('ly')) return 'adverb';
  381. if (word.toLowerCase().endsWith('ing') || word.toLowerCase().endsWith('ed')) return 'verb';
  382. if (!/^[a-z]+$/i.test(word)) return 'misspelled';
  383. return 'noun';
  384. }
  385. calculateStrength(word) {
  386. const length = word.length;
  387. if (this.isPalindrome(word)) {
  388. if (length <= 5) return { strength: 90, class: 'strong' };
  389. if (length <= 10) return { strength: 70, class: 'medium' };
  390. return { strength: 50, class: 'weak' };
  391. } else {
  392. return { strength: 30, class: 'weak' };
  393. }
  394. }
  395. addBeam() {
  396. const input = document.getElementById('palindromeInput');
  397. const word = input.value.trim();
  398. if (!word) {
  399. this.showMessage('Enter a word!', 'error');
  400. return;
  401. }
  402. const wordType = this.getWordType(word);
  403. if (this.beams.some(beam => beam.text.toLowerCase() === word.toLowerCase())) {
  404. this.showMessage('This beam already exists! Use unique words!', 'warning');
  405. return;
  406. }
  407. const { strength, class: strengthClass } = this.calculateStrength(word);
  408. const beam = {
  409. text: word,
  410. strength: strength,
  411. class: strengthClass,
  412. points: word.length * 10,
  413. wordType: wordType
  414. };
  415. this.beams.push(beam);
  416. this.beams.sort((a, b) => b.text.length - a.text.length);
  417. this.rebuild(this.beams);
  418. this.score += beam.points;
  419. const baseChange = word.length;
  420. if (wordType === 'palindrome') {
  421. this.stability = Math.min(100, this.stability + baseChange);
  422. this.showMessage(`Symmetric beam added! +${beam.points} points! Stability increased!`, 'success');
  423. if (word.length % 2 === 0) {
  424. this.score += 50;
  425. this.showMessage('Perfect symmetry bonus! +50 points!', 'success');
  426. }
  427. } else {
  428. let decreaseFactor = 8; // 700% increase for general non-pal
  429. if (['pronoun', 'verb', 'misspelled'].includes(wordType)) {
  430. decreaseFactor = 14; // 1300% increase for special
  431. }
  432. this.stability = Math.max(0, this.stability - baseChange * decreaseFactor);
  433. this.showMessage(`Asymmetric beam added! +${beam.points} points, but stability decreased!`, 'warning');
  434. }
  435. input.value = '';
  436. this.updateDisplay();
  437. if (Math.random() < this.getDisasterChanceOnAdd()) {
  438. setTimeout(() => this.triggerRandomDisaster(), 500);
  439. }
  440. }
  441. getDisasterChanceOnAdd() {
  442. return 1 / (Math.floor(Math.random() * 7) + 6); // 1/6 to 1/12
  443. }
  444. renderBeam(beam) {
  445. const palace = document.getElementById('palace');
  446. let floor = palace.querySelector('.floor:first-child');
  447. if (!floor || floor.children.length >= 3) {
  448. floor = document.createElement('div');
  449. floor.className = 'floor';
  450. palace.insertBefore(floor, palace.firstChild);
  451. this.height++;
  452. }
  453. const beamElement = document.createElement('div');
  454. beamElement.className = `beam ${beam.class}`;
  455. beamElement.textContent = beam.text;
  456. beamElement.style.setProperty('--beam-index', this.beams.length);
  457. const tooltip = document.createElement('div');
  458. tooltip.className = 'tooltip';
  459. tooltip.textContent = `Strength: ${beam.strength}% | Type: ${beam.wordType}`;
  460. beamElement.appendChild(tooltip);
  461. floor.appendChild(beamElement);
  462. }
  463. scheduleNextDisaster() {
  464. let time = 30 - (this.beams.length * 0.5);
  465. time = Math.max(10, time + (Math.random() * 20 - 10));
  466. this.autoDisasterTimer = setTimeout(() => {
  467. if (this.beams.length > 0 && this.stability > 0) {
  468. this.triggerRandomDisaster();
  469. }
  470. this.scheduleNextDisaster();
  471. }, time * 1000);
  472. }
  473. pickDisaster() {
  474. const disasters = ['Earthquake', 'Tornado', 'Tsunami', 'Volcano', 'Meteor', 'Flood'];
  475. const causes = {
  476. Earthquake: ['noun'],
  477. Tornado: ['misspelled'],
  478. Tsunami: ['adverb'],
  479. Volcano: ['verb'],
  480. Meteor: ['pronoun'],
  481. Flood: ['palindrome']
  482. };
  483. let weights = disasters.map(() => 1);
  484. this.beams.forEach(beam => {
  485. disasters.forEach((d, i) => {
  486. if (causes[d].includes(beam.wordType)) weights[i]++;
  487. });
  488. });
  489. const total = weights.reduce((a, b) => a + b, 0);
  490. let rand = Math.random() * total;
  491. for (let i = 0; i < weights.length; i++) {
  492. rand -= weights[i];
  493. if (rand < 0) return disasters[i];
  494. }
  495. return disasters[disasters.length - 1];
  496. }
  497. triggerRandomDisaster() {
  498. const type = this.pickDisaster();
  499. this.triggerDisaster(type);
  500. }
  501. triggerDisaster(type) {
  502. if (this.beams.length === 0) {
  503. this.showMessage('No palace to test!', 'error');
  504. return;
  505. }
  506. const intensity = (100 - this.stability) + Math.random() * 20;
  507. this.showMessage(`${type}! Intensity: ${Math.round(intensity)}%`, 'warning');
  508. const beamElements = document.querySelectorAll('.beam');
  509. beamElements.forEach(el => el.classList.add('shaking'));
  510. setTimeout(() => {
  511. beamElements.forEach(el => el.classList.remove('shaking'));
  512. const survivingBeams = [];
  513. let collapsed = false;
  514. this.beams.forEach((beam, index) => {
  515. let survivalChance = beam.strength / 100;
  516. const effects = this.disasterEffects[type];
  517. if (effects) {
  518. if (effects.prone.includes(beam.wordType)) survivalChance *= 0.5;
  519. if (effects.resistant.includes(beam.wordType)) survivalChance *= 1.5;
  520. }
  521. survivalChance = Math.min(1, survivalChance);
  522. const survives = Math.random() < survivalChance || intensity < 50;
  523. if (!survives) {
  524. collapsed = true;
  525. beamElements[index].classList.add('collapsing');
  526. } else {
  527. survivingBeams.push(beam);
  528. }
  529. });
  530. if (collapsed) {
  531. setTimeout(() => this.rebuild(survivingBeams), 1000);
  532. } else {
  533. this.showMessage(`Your palace withstood the ${type}! Magnificent engineering!`, 'success');
  534. this.score += 100;
  535. this.updateDisplay();
  536. }
  537. }, 1000);
  538. }
  539. rebuild(survivingBeams) {
  540. survivingBeams.sort((a, b) => b.text.length - a.text.length);
  541. const lostBeams = this.beams.length - survivingBeams.length;
  542. let lostStability = 0;
  543. const removedBeams = this.beams.filter(b => !survivingBeams.includes(b));
  544. removedBeams.forEach(beam => {
  545. if (beam.wordType === 'palindrome') {
  546. lostStability += 20;
  547. } else {
  548. lostStability += 5;
  549. }
  550. });
  551. this.stability = Math.max(0, this.stability - lostStability);
  552. this.showMessage(`${lostBeams} beams collapsed! Rebuilding...`, 'error');
  553. const palace = document.getElementById('palace');
  554. palace.innerHTML = '<div id="foundation"></div>';
  555. this.beams = [];
  556. this.height = 0;
  557. survivingBeams.forEach(beam => {
  558. this.beams.push(beam);
  559. this.renderBeam(beam);
  560. });
  561. this.updateDisplay();
  562. }
  563. shake(element) {
  564. element.style.animation = 'shake 0.5s';
  565. setTimeout(() => element.style.animation = '', 500);
  566. }
  567. showMessage(text, type) {
  568. const message = document.getElementById('message');
  569. message.textContent = text;
  570. message.className = type;
  571. message.style.display = 'block';
  572. setTimeout(() => {
  573. message.style.display = 'none';
  574. }, 2500);
  575. }
  576. updateDisplay() {
  577. document.getElementById('height').textContent = this.height;
  578. document.getElementById('stability').textContent = this.stability;
  579. document.getElementById('score').textContent = this.score;
  580. const riskElement = document.getElementById('disasterRisk');
  581. if (this.stability > 75) {
  582. riskElement.textContent = 'Low';
  583. riskElement.style.color = '#00ff00';
  584. } else if (this.stability > 50) {
  585. riskElement.textContent = 'Medium';
  586. riskElement.style.color = '#ffff00';
  587. } else {
  588. riskElement.textContent = 'High';
  589. riskElement.style.color = '#ff0000';
  590. }
  591. if (this.stability <= 0) {
  592. this.gameOver();
  593. }
  594. }
  595. gameOver() {
  596. this.showMessage(`Stability reached 0%! Palace destroyed! Final Score: ${this.score}`, 'error');
  597. setTimeout(() => this.resetGame(), 3000);
  598. }
  599. resetGame() {
  600. this.beams = [];
  601. this.score = 0;
  602. this.stability = 100;
  603. this.height = 0;
  604. const palace = document.getElementById('palace');
  605. palace.innerHTML = '<div id="foundation"></div>';
  606. this.updateDisplay();
  607. }
  608. }
  609. // Initialize the game
  610. const game = new PalindromePalace();
  611. </script>
  612. </body>
  613. </html>
  614.  
Advertisement
Add Comment
Please, Sign In to add comment