PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/memory/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / memory
Files
3 (README)(gnomod.toml)
Exported functions
3
Module
gno.land/r/moul/x/daily/memory/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • memory.gnogno
memory.gnogno
1// Package memory implements "Memory Match", a concentration game on a2// 4x4 grid of 8 emoji pairs. The board is shuffled deterministically from3// the current block height (no on-chain RNG exists), so a NewGame started at4// a given height always produces the same layout.5package memory67import (8	"strconv"9	"strings"1011	"chain"12	"chain/runtime"13)1415const gridSize = 16 // 4x416const numPairs = 81718// faces are the 8 distinct emoji; each appears exactly twice on the board.19var faces = [numPairs]string{"🐶", "🐱", "🦊", "🐸", "🐵", "🐼", "🦁", "🐧"}2021// tile holds the face index (0..7) for a cell and whether it is matched.22type tile struct {23	face    int24	matched bool25}2627// board is the full game state. It is a package-level singleton so the realm28// persists a single shared game.29var board = struct {30	tiles   [gridSize]tile31	flipped []int // indices currently face-up but not yet resolved (0, 1 or 2)32	moves   int   // number of completed two-tile attempts33	pairs   int   // matched pairs so far34	height  int64 // block height the current game was seeded from35	started bool36}{}3738// shuffle produces a deterministic permutation of the 16 tile faces from a39// 64-bit seed. It fills a slice with two of each face index then applies a40// Fisher-Yates shuffle driven by a simple LCG — fully deterministic, no RNG.41func shuffle(seed int64) [gridSize]tile {42	vals := make([]int, 0, gridSize)43	for i := 0; i < numPairs; i++ {44		vals = append(vals, i, i)45	}46	// LCG (Numerical Recipes constants); force unsigned-style math via uint64.47	state := uint64(seed)*6364136223846793005 + 144269504088896340748	for i := len(vals) - 1; i > 0; i-- {49		state = state*6364136223846793005 + 144269504088896340750		j := int(state % uint64(i+1))51		vals[i], vals[j] = vals[j], vals[i]52	}53	var out [gridSize]tile54	for i := 0; i < gridSize; i++ {55		out[i] = tile{face: vals[i], matched: false}56	}57	return out58}5960func ensureStarted() {61	if !board.started {62		reset(runtime.ChainHeight())63	}64}6566func reset(height int64) {67	board.tiles = shuffle(height)68	board.flipped = nil69	board.moves = 070	board.pairs = 071	board.height = height72	board.started = true73}7475// NewGame reshuffles the board using the current block height as the seed.76func NewGame(cur realm) {77	reset(runtime.ChainHeight())78	chain.Emit("NewGame", "height", strconv.FormatInt(board.height, 10))79}8081// Flip reveals the tile at index (0..15).82//83// Rules:84//   - If two tiles are already showing from a previous unmatched attempt,85//     this Flip first clears them (they turn back to hidden), then reveals86//     the requested tile as the first of a new attempt.87//   - Revealing the second tile of an attempt completes a move: matching88//     faces stay face-up (matched); a mismatch leaves both showing until the89//     next Flip clears them.90//   - Flipping an already-matched or already-showing tile is rejected.91func Flip(cur realm, index int) {92	ensureStarted()9394	if index < 0 || index >= gridSize {95		panic("index out of range")96	}97	if board.tiles[index].matched {98		panic("tile already matched")99	}100101	// A completed unmatched attempt (2 face-up, non-matching) is cleared102	// before the next reveal.103	if len(board.flipped) == 2 {104		board.flipped = nil105	}106107	for _, f := range board.flipped {108		if f == index {109			panic("tile already flipped")110		}111	}112113	board.flipped = append(board.flipped, index)114115	if len(board.flipped) != 2 {116		chain.Emit("Flip", "index", strconv.Itoa(index))117		return118	}119120	// Second tile of the attempt: resolve.121	board.moves++122	a, b := board.flipped[0], board.flipped[1]123	if board.tiles[a].face == board.tiles[b].face {124		board.tiles[a].matched = true125		board.tiles[b].matched = true126		board.pairs++127		board.flipped = nil128		chain.Emit("Match", "index", strconv.Itoa(index), "pairs", strconv.Itoa(board.pairs))129	} else {130		// leave both showing; next Flip clears them131		chain.Emit("Miss", "index", strconv.Itoa(index))132	}133}134135func solved() bool {136	return board.pairs == numPairs137}138139// cellFace returns the emoji to display for a cell given the current state.140func cellFace(i int) string {141	if board.tiles[i].matched {142		return faces[board.tiles[i].face]143	}144	for _, f := range board.flipped {145		if f == i {146			return faces[board.tiles[i].face]147		}148	}149	return "❓"150}151152// Render draws the board as Markdown: a 4x4 grid, move count and solved state.153func Render(path string) string {154	ensureStarted()155156	var sb strings.Builder157	sb.WriteString("# 🧠 Memory Match\n\n")158	sb.WriteString("Match all 8 emoji pairs on the 4x4 grid.\n\n")159160	sb.WriteString("| | | | |\n")161	sb.WriteString("|:-:|:-:|:-:|:-:|\n")162	for row := 0; row < 4; row++ {163		sb.WriteString("|")164		for col := 0; col < 4; col++ {165			sb.WriteString(" " + cellFace(row*4+col) + " |")166		}167		sb.WriteString("\n")168	}169170	sb.WriteString("\n")171	sb.WriteString("- Moves: **" + strconv.Itoa(board.moves) + "**\n")172	sb.WriteString("- Pairs matched: **" + strconv.Itoa(board.pairs) + " / " + strconv.Itoa(numPairs) + "**\n")173	sb.WriteString("- Seed height: **" + strconv.FormatInt(board.height, 10) + "**\n\n")174175	if solved() {176		sb.WriteString("🎉 **Solved in " + strconv.Itoa(board.moves) + " moves!** Call `NewGame` to play again.\n")177	} else {178		sb.WriteString("Call `Flip(index)` with a cell index 0–15. `NewGame()` reshuffles.\n")179	}180181	return sb.String()182}183

Functions

  • Flip(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, index int)

  • NewGame(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string})

  • Render(path string) string

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.