stack.gno
3.56 Kb · 113 lines
1// Package stack is an educational data-structure playground that keeps BOTH a
2// LIFO stack and a FIFO queue of ints, so you can compare how the two behave.
3package stack
4
5import (
6 "chain"
7 "strconv"
8 "strings"
9)
10
11// stackData holds the LIFO stack; the last pushed element is the "top".
12var stackData []int
13
14// queueData holds the FIFO queue; the oldest enqueued element is the "front".
15var queueData []int
16
17// Push adds n to the top of the LIFO stack.
18func Push(cur realm, n int) {
19 stackData = append(stackData, n)
20 chain.Emit("Push", "n", strconv.Itoa(n), "size", strconv.Itoa(len(stackData)))
21}
22
23// Pop removes and returns the top element of the LIFO stack.
24// It panics (a cross-realm abort) if the stack is empty.
25func Pop(cur realm) int {
26 if len(stackData) == 0 {
27 panic("stack is empty: nothing to pop")
28 }
29 last := len(stackData) - 1
30 n := stackData[last]
31 stackData = stackData[:last]
32 chain.Emit("Pop", "n", strconv.Itoa(n), "size", strconv.Itoa(len(stackData)))
33 return n
34}
35
36// Enqueue adds n to the back of the FIFO queue.
37func Enqueue(cur realm, n int) {
38 queueData = append(queueData, n)
39 chain.Emit("Enqueue", "n", strconv.Itoa(n), "size", strconv.Itoa(len(queueData)))
40}
41
42// Dequeue removes and returns the front element of the FIFO queue.
43// It panics (a cross-realm abort) if the queue is empty.
44func Dequeue(cur realm) int {
45 if len(queueData) == 0 {
46 panic("queue is empty: nothing to dequeue")
47 }
48 n := queueData[0]
49 queueData = queueData[1:]
50 chain.Emit("Dequeue", "n", strconv.Itoa(n), "size", strconv.Itoa(len(queueData)))
51 return n
52}
53
54// StackSize returns the number of elements in the LIFO stack.
55func StackSize() int { return len(stackData) }
56
57// QueueSize returns the number of elements in the FIFO queue.
58func QueueSize() int { return len(queueData) }
59
60// renderInts formats a slice of ints as a space-separated list, e.g. "1 2 3".
61func renderInts(xs []int) string {
62 if len(xs) == 0 {
63 return "_(empty)_"
64 }
65 parts := make([]string, len(xs))
66 for i, x := range xs {
67 parts[i] = strconv.Itoa(x)
68 }
69 return "`" + strings.Join(parts, " ") + "`"
70}
71
72// Render returns a Markdown view of both structures with top/front labeled,
73// their sizes, and a one-line explanation of LIFO vs FIFO.
74func Render(path string) string {
75 var b strings.Builder
76
77 b.WriteString("# Stack & Queue Playground\n\n")
78 b.WriteString("A **stack** is LIFO (last in, first out) — the last item pushed is the first popped. ")
79 b.WriteString("A **queue** is FIFO (first in, first out) — the first item enqueued is the first dequeued.\n\n")
80
81 b.WriteString("## Stack (LIFO) — size ")
82 b.WriteString(strconv.Itoa(len(stackData)))
83 b.WriteString("\n\n")
84 b.WriteString("Contents (bottom → top): ")
85 b.WriteString(renderInts(stackData))
86 b.WriteString("\n\n")
87 if len(stackData) > 0 {
88 b.WriteString("Top: `")
89 b.WriteString(strconv.Itoa(stackData[len(stackData)-1]))
90 b.WriteString("` — the next `Pop` returns this.\n\n")
91 } else {
92 b.WriteString("Top: _(none)_ — `Pop` would panic.\n\n")
93 }
94
95 b.WriteString("## Queue (FIFO) — size ")
96 b.WriteString(strconv.Itoa(len(queueData)))
97 b.WriteString("\n\n")
98 b.WriteString("Contents (front → back): ")
99 b.WriteString(renderInts(queueData))
100 b.WriteString("\n\n")
101 if len(queueData) > 0 {
102 b.WriteString("Front: `")
103 b.WriteString(strconv.Itoa(queueData[0]))
104 b.WriteString("` — the next `Dequeue` returns this.\n\n")
105 } else {
106 b.WriteString("Front: _(none)_ — `Dequeue` would panic.\n\n")
107 }
108
109 b.WriteString("---\n\n")
110 b.WriteString("_Tip: push the same sequence into both, then Pop vs Dequeue to see LIFO reverse it while FIFO preserves order._\n")
111
112 return b.String()
113}