v/examples/gg/memory.v
Eliyaan (Nopana) bbb61ab368
Some checks failed
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run
Workflow Lint / lint-yml-workflows (push) Has been cancelled
gg, gx: deprecate gx and replace all occurences with gg (which now contains all the functionality of gx) (#24966)
2025-08-14 19:53:56 +03:00

134 lines
3.2 KiB
V

module main
import gg
import rand
import time
const cover = gg.rgba(85, 200, 85, 255)
const csize = 120 // cell size in pixels
const letters = 'AABBOOCCVVXXYYZZMMKKHHTT'.split('')
const header_size = 30
struct Cell {
mut:
is_open bool
letter string
}
struct Game {
mut:
ctx &gg.Context = unsafe { nil }
cells []Cell
card1_idx ?int
card2_idx ?int
size int // in cells
remaining int
sw time.StopWatch = time.new_stopwatch()
revert_sw time.StopWatch = time.new_stopwatch(auto_start: false)
}
fn (mut g Game) restart() {
ncells := g.size * g.size
g.remaining = ncells
g.cells = []Cell{len: ncells, init: Cell{
letter: letters[index % letters.len]
}}
rand.shuffle(mut g.cells) or {}
g.sw = time.new_stopwatch()
g.card1_idx = none
g.card2_idx = none
}
fn (mut g Game) draw_cell(i int, cell Cell) {
x, y := i % g.size, i / g.size
rect_x, rect_y := x * csize, header_size + y * csize
if g.cells[i].is_open || g.sw.elapsed().milliseconds() <= 1000 {
lsize := 96
g.ctx.draw_rect_empty(rect_x + 6, rect_y + 6, csize - 10, csize - 10, gg.light_gray)
g.ctx.draw_text(rect_x + csize / 2 - lsize / 3, rect_y + csize / 2 - lsize / 2,
g.cells[i].letter, color: gg.yellow, size: lsize)
} else {
g.ctx.draw_rect_filled(rect_x + 6, rect_y + 6, csize - 10, csize - 10, cover)
}
}
fn on_frame(mut g Game) {
ws := gg.window_size()
g.ctx.begin()
message := '(r)estart (esc)ape | remaining: ${g.remaining:02} | time: ${f64(g.sw.elapsed().milliseconds()) / 1000.0:06.1f}s'
g.ctx.draw_text(ws.width / 2, 7, message, color: gg.light_gray, size: 22, align: .center)
for i, cell in g.cells {
g.draw_cell(i, cell)
}
if g.revert_sw.elapsed().milliseconds() > 750 {
g.revert_sw = time.new_stopwatch(auto_start: false)
if g.card1_idx != none {
if g.card2_idx != none {
g.cells[g.card1_idx].is_open = false
g.cells[g.card2_idx].is_open = false
g.card1_idx = none
g.card2_idx = none
g.remaining = g.cells.count(!it.is_open)
}
}
}
g.ctx.end()
}
fn on_event(e &gg.Event, mut g Game) {
if e.typ == .key_down {
match e.key_code {
.escape { g.ctx.quit() }
.r { g.restart() }
else {}
}
return
}
if e.typ != .mouse_down {
return
}
x, y := int(e.mouse_x / csize), int((e.mouse_y - header_size) / csize)
if e.mouse_button == .left && g.card2_idx == none {
if g.remaining == 0 {
g.restart()
return
}
i := y * g.size + x
if !g.cells[i].is_open {
g.cells[i].is_open = true
if g.card1_idx == none {
g.card1_idx = i
} else {
g.card2_idx = i
if g.cells[g.card1_idx].letter == g.cells[i].letter {
g.card1_idx = none
g.card2_idx = none
} else {
// start a timer, that will be checked in the on_frame callback
g.revert_sw.start()
}
}
}
}
g.remaining = g.cells.count(!it.is_open)
if g.remaining == 0 {
g.sw.stop()
}
}
mut g := &Game{
// the CLI argument should be number of pairs, so `size` is even, and the puzzle can be solved:
size: arguments()[1] or { '3' }.int() * 2
}
g.restart()
g.ctx = gg.new_context(
bg_color: gg.black
width: g.size * csize
height: header_size + g.size * csize
window_title: 'V Memory ${g.size} x ${g.size}'
user_data: g
frame_fn: on_frame
event_fn: on_event
sample_count: 2
)
g.ctx.run()