Created
April 20, 2025 20:44
-
-
Save jaysephjw/df5b190ddb3ef9874cfbcefd79aaad9e to your computer and use it in GitHub Desktop.
Market Go - a go game variant
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Market Go</title> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
min-height: 100vh; | |
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf2 100%); | |
padding: 1rem; | |
margin: 0; | |
} | |
.title { | |
font-size: 1.5rem; | |
font-weight: bold; | |
margin-bottom: 2rem; | |
} | |
.subtitle { | |
font-size: 1.25rem; | |
font-weight: 600; | |
margin-bottom: 1rem; | |
} | |
.cards-container { | |
display: flex; | |
flex-wrap: wrap; | |
justify-content: center; | |
gap: 1rem; | |
margin-bottom: 2rem; | |
} | |
.card { | |
background-color: white; | |
border-radius: 0.5rem; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
padding: 1rem; | |
width: 16rem; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
} | |
.card-content { | |
position: relative; | |
width: 100%; | |
height: 6rem; | |
margin-bottom: 1rem; | |
} | |
.move-display { | |
position: absolute; | |
inset: 0; | |
border: 2px solid #d1d5db; | |
border-radius: 0.5rem; | |
padding: 0.75rem; | |
width: 100%; | |
height: 100%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
background-color: #f9fafb; | |
transition: all 1s; | |
box-sizing: border-box; | |
} | |
.move-text { | |
text-align: center; | |
font-size: 1.125rem; | |
} | |
.refresh-button { | |
background-color: #3b82f6; | |
color: white; | |
font-weight: bold; | |
padding: 0.5rem 1rem; | |
border-radius: 0.25rem; | |
border: none; | |
font-size: 0.875rem; | |
cursor: pointer; | |
} | |
.refresh-button:hover { | |
background-color: #2563eb; | |
} | |
.refresh-button:disabled { | |
opacity: 0.5; | |
cursor: not-allowed; | |
} | |
.rules-container { | |
width: 100%; | |
max-width: 42rem; | |
background-color: white; | |
border-radius: 0.5rem; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
padding: 1.5rem; | |
margin-bottom: 1.5rem; | |
} | |
.rules-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
cursor: pointer; | |
} | |
.rules-title { | |
font-size: 1.25rem; | |
font-weight: 600; | |
} | |
.rules-icon { | |
width: 1.25rem; | |
height: 1.25rem; | |
color: #6b7280; | |
} | |
.rules-content { | |
margin-top: 1rem; | |
} | |
.rules-list { | |
list-style-type: decimal; | |
padding-left: 1.5rem; | |
} | |
.rules-list li { | |
margin-bottom: 0.5rem; | |
} | |
.rules-subtitle { | |
font-size: 1.125rem; | |
font-weight: 500; | |
margin-top: 1rem; | |
margin-bottom: 0.5rem; | |
} | |
.hidden { | |
display: none; | |
} | |
.animating { | |
opacity: 0; | |
transform: translateY(-0.5rem) scale(0.95); | |
} | |
</style> | |
</head> | |
<body> | |
<div class="title">Market Go</div> | |
<div class="subtitle">Move Market</div> | |
<div class="cards-container" id="cards-container"> | |
<!-- Cards will be generated via JavaScript --> | |
</div> | |
<div class="rules-container"> | |
<div class="rules-header" id="rules-header"> | |
<h2 class="rules-title">Rules</h2> | |
<div class="rules-icon" id="rules-icon"> | |
<!-- SVG for chevron up --> | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<polyline points="18 15 12 9 6 15"></polyline> | |
</svg> | |
</div> | |
</div> | |
<div class="rules-content" id="rules-content"> | |
<ol class="rules-list"> | |
<li>Begin with 2 star points each.</li> | |
<li>Each turn, a player must select a move from the market. Their next stone must be played according to that move type.</li> | |
<li>After playing a move, the player presses 'Refresh' on that move. Moves are relative only to your own stones.</li> | |
<li>"Single Point" moves are legal only at points un-reachable by any of the other possible move type (no matter what is in the current market).</li> | |
<li>Re-rolling 3 Single-Points: If all market moves are 'Single Point', AND the player has no legal single-point moves, they must re-roll all 3 move cards.</li> | |
</ol> | |
<p style="font-style: italic; margin-top: 1rem;"> | |
There may be many ways of reaching the same point. For example, a kosumi may also be a knight's move from a more distant stone. Just declare a reference point for your move if there is ambiguity. | |
</p> | |
</div> | |
</div> | |
<script> | |
// Shared collection of Go moves | |
const moves = [ | |
"Single point", | |
"One space jump", | |
"Two space jump", | |
"Knights move", | |
"Large knights move", | |
"Nobi (extend)", | |
"Kosumi (diagonal)" | |
]; | |
// Get random move, avoiding the current move if specified | |
function getRandomMove(currentMove = null) { | |
let newMove; | |
do { | |
const randomIndex = Math.floor(Math.random() * moves.length); | |
newMove = moves[randomIndex]; | |
} while (newMove === currentMove && moves.length > 1); | |
return newMove; | |
} | |
// Create a card element with a random move | |
function createCard(index) { | |
const initialMove = getRandomMove(); | |
const card = document.createElement('div'); | |
card.className = 'card'; | |
card.id = `card-${index}`; | |
const cardContent = document.createElement('div'); | |
cardContent.className = 'card-content'; | |
const moveDisplay = document.createElement('div'); | |
moveDisplay.className = 'move-display'; | |
moveDisplay.id = `move-display-${index}`; | |
const moveText = document.createElement('p'); | |
moveText.className = 'move-text'; | |
moveText.textContent = initialMove; | |
moveText.id = `move-text-${index}`; | |
moveDisplay.appendChild(moveText); | |
cardContent.appendChild(moveDisplay); | |
const refreshButton = document.createElement('button'); | |
refreshButton.className = 'refresh-button'; | |
refreshButton.textContent = 'Refresh'; | |
refreshButton.id = `refresh-button-${index}`; | |
refreshButton.addEventListener('click', () => { | |
// Check if already animating | |
if (moveDisplay.classList.contains('animating')) return; | |
// Get current move | |
const currentMove = moveText.textContent; | |
// Start animation | |
moveDisplay.classList.add('animating'); | |
refreshButton.disabled = true; | |
// Get a new move | |
const newMove = getRandomMove(currentMove); | |
// Update after animation | |
setTimeout(() => { | |
moveText.textContent = newMove; | |
moveDisplay.classList.remove('animating'); | |
refreshButton.disabled = false; | |
}, 500); | |
}); | |
card.appendChild(cardContent); | |
card.appendChild(refreshButton); | |
return card; | |
} | |
// Initialize the app | |
function initApp() { | |
const cardsContainer = document.getElementById('cards-container'); | |
// Create 3 cards | |
for (let i = 0; i < 3; i++) { | |
const card = createCard(i); | |
cardsContainer.appendChild(card); | |
} | |
// Setup rules toggle | |
const rulesHeader = document.getElementById('rules-header'); | |
const rulesContent = document.getElementById('rules-content'); | |
const rulesIcon = document.getElementById('rules-icon'); | |
rulesHeader.addEventListener('click', () => { | |
const isOpen = !rulesContent.classList.contains('hidden'); | |
if (isOpen) { | |
rulesContent.classList.add('hidden'); | |
// Change to chevron down | |
rulesIcon.innerHTML = ` | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<polyline points="6 9 12 15 18 9"></polyline> | |
</svg> | |
`; | |
} else { | |
rulesContent.classList.remove('hidden'); | |
// Change to chevron up | |
rulesIcon.innerHTML = ` | |
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<polyline points="18 15 12 9 6 15"></polyline> | |
</svg> | |
`; | |
} | |
}); | |
} | |
// Initialize when DOM is loaded | |
document.addEventListener('DOMContentLoaded', initApp); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment