Robin’s nest

Mama Robin on flag
Babies in the nest
Cat / Robin standoff

Morning window-light, cat perched sentinel, ears flicking at the robin’s sharp tut-tut-tut from the flag stake outside. She has claimed the yard as her kingdom for now. Her breast is bright as ember, feathers ruffled with purpose. Every step past the hedge, every tilt of the curtain, draws her vigilance. I imagine her heart beating faster than my own, a drumbeat of protection.

Later, I peek into the maple and find the reason: two tiny beaks stretching skyward, tufted crowns of down and pinfeathers, not yet ready to know the sky. The nest is a woven cradle of sticks and hope, a cradle that breathes with each soft tremor of chicks begging for more. Their eyes are half-closed, but their hunger burns awake.

The robin watches me watching, neither of us entirely trusting, but both bound to this moment. She sings less now, too busy with duty, worms plucked from the damp soil and delivered with tenderness disguised as efficiency. Fierce and tireless, a flame against the green world.

The cat sighs from the sill, thwarted hunter behind glass, while I feel the tug of seasons, how life unfurls in branches, how small voices become the loud chorus of summer. For now, the robin stands guard, and I stand witness.

The butterfly emerges!

Monarch out of the chrysalis

the hanging lantern opened

early afternoon, porch still cool. stepped outside to find a small miracle clinging under the eaves. a monarch had slipped free from its glassy coffin. wings damp, folded tight, slowly breathing into shape. the chrysalis above it, once green and gold, now nothing more than a hollow paper lantern. finished.

the butterfly trembled against it, orange sails heavy with gravity. veins filling, colors darkening, each beat of the heart writing a little more of the story in black and gold.

thoughts drifted toward patience. all that unseen work in silence, days of dissolution and rearrangement, until one quiet morning something new opens its eyes. sunlight stitched into wings. the world noisy all around, but here was proof of stillness doing its work.

fragile. defiant. not yet ready for air. it hangs and waits, wings drying, gathering strength. i wait too. remembering that emergence takes its own time.

milkweed moves in the breeze. far south, a forest waits. for now, just this bright spark, clinging to its empty lantern, preparing.

today, i witnessed transformation. tomorrow, it will be gone, riding the wind.

🦋

current mood: quiet delight
current music: wind through leaves, somewhere a dove calling

#roanokeva
#monarch #butterfly #chrysalis

Day 20,660 It’s the monarch!

Over the front door, a chrysalis hangs. Monarch. Green jade lantern with a seam of gold, balanced in its little hook. I open the door and it sways just slightly, steadying again, as if nothing at all can disturb its long dream.

It changes there, unseen. Inside, the body is rewritten, cells unspooling, wings folded like secret letters. From the outside, only stillness, except for the shimmer of gold dots, like stars pinned to its surface.

Every time I step out, I look up. A reminder. A spell. The threshold feels different with this little guardian over it, a quiet companion of the in between. Doorways are always a kind of crossing. This one now more so.

Soon it will split, and from silence will come the crackle of wings, orange and black, lifting into air. For now, I pass under it, carrying the hush of transformation into my day.

Number converter – python

# number_converter.py
# Works in Pydroid 3 (Android Python environment)

import inflect

# Create engine for number-to-words
p = inflect.engine()

# Function to convert to Roman numerals
def to_roman(num):
    if not (0 < num < 4000):
        return “Roman numerals only support 1–3999”
    values = [
        (1000, “M”), (900, “CM”), (500, “D”), (400, “CD”),
        (100, “C”), (90, “XC”), (50, “L”), (40, “XL”),
        (10, “X”), (9, “IX”), (5, “V”), (4, “IV”), (1, “I”)
    ]
    result = “”
    for val, symbol in values:
        while num >= val:
            result += symbol
            num -= val
    return result

# Function to convert number to binary
def to_binary(num):
    return bin(num)[2:]

# Function to convert number to hexadecimal
def to_hex(num):
    return hex(num)[2:].upper()

# Function to convert number to words
def to_words(num):
    return p.number_to_words(num)

# Main interactive loop
def main():
    while True:
        try:
            num = int(input(“\nEnter a number (or -1 to quit): “))
            if num == -1:
                print(“Goodbye!”)
                break

            print(“\nChoose conversion:”)
            print(“1. Roman Numerals”)
            print(“2. Binary”)
            print(“3. Hexadecimal”)
            print(“4. Words”)

            choice = input(“Enter choice (1-4): “)

            if choice == “1”:
                print(“Roman Numeral:”, to_roman(num))
            elif choice == “2”:
                print(“Binary:”, to_binary(num))
            elif choice == “3”:
                print(“Hexadecimal:”, to_hex(num))
            elif choice == “4”:
                print(“Words:”, to_words(num))
            else:
                print(“Invalid choice!”)

        except ValueError:
            print(“Please enter a valid integer.”)

if __name__ == “__main__”:
    main()

Summoning breakfast in the form of a fish for the kitty-boss

The cat has made me into a wizard, at least in the quiet story she tells with her eyes. She believes I can summon food from the hidden places. An empty bowl waits, and with a few simple gestures, it is full again. To her, this is not routine – it is magic.

She approaches with ceremony: weaving circles around my legs, chanting her meows, tail coiling like a ribbon of smoke. Each time she comes, it feels like a chapter retold – the faithful one calling upon the hearth wizard to bring forth plenty. I answer, as good wizards do. The bowl fills, and the covenant holds true.

In her folklore, I suspect she keeps me as the household mage, draped not in robes but in the ordinary, bending the world to keep her safe and fed. She believes in the ritual completely, and there is power in being so believed in.

She eats, and her purr is the hymn that seals the tale – a soft song of trust, love and satisfaction.

And outside, the day lingers. The cicadas chant, the stars scratch their worn runes across the sky… the sun and moon drift above us like gold and silver lanterns.

In moments like these, it feels true enough: the simplest acts are often the deepest spells, and love itself is the oldest magic we know.

#doodle #digitalmarkers #roanokeva #cat #magic #love #hungry #fish

Day 20,658



Morning robot divination, the runes clattered out:

ᚱ Raidho – the road, the turning wheel, journeys both on foot and inward.

ᛗ Mannaz – humanity, cooperation, the reflection of self through others.

ᚺ Hagalaz – hail, disruption, sudden ice cracking branches, unasked but clarifying.

Together, a reminder: movement is happening, best shared with others, even if the storm comes along to shake it all loose.

The I Ching followed with Hexagram 53 – 漸 (Jiàn), Gradual Progress. The lines stacked like this:

7 —   (young yang)
9 — — (old yang, changing to yin)
6 —   (old yin, changing to yang)
7 —   (young yang)
8 — — (young yin)
8 — — (young yin)

Like the flight of the wild goose: slow, patient, finding safe landings step by step. The changes in the middle — strength softening, softness firming — say that flexibility is part of progress.

So the whole spread leans into:

ᚱ the road opens,

ᛗ companionship matters,

ᚺ the storm disrupts,

but 漸 Gradual Progress carries through, steady wings in the long arc of travel.


Later, I walked the greenway and watched a gaggle of geese settling at the water’s edge, right on cue. The sky broke open with a shaft of sunlight between gray banks of cloud. A couple of strangers paused to chat at the benches  – small, welcome echoes of ᛗ. Storm brewing on the horizon, but storms move on. Step by step, wheel by wheel, goose by goose.

Polygons python test

I need to work on the 12 sider

Showing 20 sider

import pygame
import math

# — Configuration —
WIDTH, HEIGHT = 800, 600
BACKGROUND_COLOR = (10, 10, 20)      # Dark Blue-Gray
LINE_COLOR = (255, 255, 255)         # White
ROTATION_SPEED = 0.01

# — Menu Configuration —
pygame.font.init()
try:
    MENU_FONT = pygame.font.SysFont(“sans”, 28)
except:
    MENU_FONT = pygame.font.Font(None, 36)

MENU_TEXT_COLOR = (200, 200, 200) # Light Gray
MENU_HIGHLIGHT_COLOR = (255, 215, 0) # Gold
MENU_BACKGROUND_COLOR = (30, 30, 40)
MENU_WIDTH = 220

# — Platonic Solid Data —
def get_platonic_solid_data(name):
    “””Provides the correctly scaled vertices and faces for a given Platonic solid.”””

    if name == “Tetrahedron”:
        scale = 150
        v_base = [(1,1,1), (-1,-1,1), (-1,1,-1), (1,-1,-1)]
        f = [(0,1,2), (0,2,3), (0,3,1), (1,3,2)]
        v = [(p[0]*scale, p[1]*scale, p[2]*scale) for p in v_base]
        return v, f

    if name == “Cube”:
        scale = 130
        v_base = [(-1,-1,1), (1,-1,1), (1,1,1), (-1,1,1),
                  (-1,-1,-1), (1,-1,-1), (1,1,-1), (-1,1,-1)]
        f = [(0,1,2,3), (4,5,1,0), (5,6,2,1), (6,7,3,2), (7,4,0,3), (7,6,5,4)]
        v = [(p[0]*scale, p[1]*scale, p[2]*scale) for p in v_base]
        return v, f

    if name == “Octahedron”:
        scale = 160
        v_base = [(0,0,1), (0,0,-1), (1,0,0), (-1,0,0), (0,1,0), (0,-1,0)]
        f = [(0,2,4), (0,4,3), (0,3,5), (0,5,2), (1,2,5), (1,5,3), (1,3,4), (1,4,2)]
        v = [(p[0]*scale, p[1]*scale, p[2]*scale) for p in v_base]
        return v, f

    if name == “Dodecahedron”:
        # — CORRECTED AND VERIFIED DATA —
        scale = 100
        phi = (1 + math.sqrt(5)) / 2
        v_base = [
            (-1, -1, -1), ( 1, -1, -1), ( 1,  1, -1), (-1,  1, -1),
            (-1, -1,  1), ( 1, -1,  1), ( 1,  1,  1), (-1,  1,  1),
            (0, -1/phi, -phi), (0, -1/phi,  phi), (0,  1/phi, -phi), (0,  1/phi,  phi),
            (-1/phi, -phi, 0), ( 1/phi, -phi, 0), (-1/phi,  phi, 0), ( 1/phi,  phi, 0),
            (-phi, 0, -1/phi), ( phi, 0, -1/phi), ( phi, 0,  1/phi), (-phi, 0,  1/phi)
        ]
        f = [
            (3, 11,  7, 18, 19), (3, 19, 16,  2, 14), (3, 14, 15,  1, 11),
            (7, 11,  1,  5, 18), (1,  5, 13,  0, 10), (5, 13,  4, 17, 18),
            (4, 13,  0,  8, 12), (0,  8, 16, 19, 18), (2, 14, 15,  9, 10),
            (6, 17,  8, 12, 16), (6, 12,  4, 13, 5), (6, 17,  9, 15, 14)
        ]
        v = [(p[0]*scale, p[1]*scale, p[2]*scale) for p in v_base]
        return v, f

    if name == “Icosahedron”:
        scale = 130
        phi = (1 + math.sqrt(5)) / 2
        v_base = [
            (-1, phi, 0), ( 1, phi, 0), (-1, -phi, 0), ( 1, -phi, 0),
            (0, -1, phi), (0, 1, phi), (0, -1, -phi), (0, 1, -phi),
            (phi, 0, -1), (phi, 0, 1), (-phi, 0, -1), (-phi, 0, 1)
        ]
        f = [
            (0, 11, 5), (0, 5, 1), (0, 1, 7), (0, 7, 10), (0, 10, 11), (1, 5, 9),
            (5, 11, 4), (11, 10, 2), (10, 7, 6), (7, 1, 8), (3, 9, 4), (3, 4, 2),
            (3, 2, 6), (3, 6, 8), (3, 8, 9), (4, 9, 5), (2, 4, 11), (6, 2, 10),
            (8, 6, 7), (9, 8, 1)
        ]
        v = [(p[0]*scale, p[1]*scale, p[2]*scale) for p in v_base]
        return v, f

# — State Variables —
solid_names = [“Tetrahedron”, “Cube”, “Octahedron”, “Icosahedron”, “Dodecahedron”]
current_solid_name = solid_names[0]
vertices, faces = [], []
angle_x, angle_y, angle_z = 0, 0, 0

# — Function to load a solid —
def load_solid(name):
    global current_solid_name, vertices, faces, angle_x, angle_y, angle_z
    current_solid_name = name
    vertices, faces = get_platonic_solid_data(name)
    angle_x, angle_y, angle_z = 0, 0, 0

# — Build Menu Items —
menu_rects = {}
y_offset = 20
for name in solid_names:
    text_surf = MENU_FONT.render(name, True, MENU_TEXT_COLOR)
    rect = text_surf.get_rect(topleft=(20, y_offset))
    menu_rects[name] = rect
    y_offset += 40

# — Pygame Setup —
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(“Select and Spin a Platonic Solid”)
clock = pygame.time.Clock()
load_solid(current_solid_name)

# — Main Loop —
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: running = False
        if event.type == pygame.KEYDOWN and event.key == pygame.K_AC_BACK: running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                for name, rect in menu_rects.items():
                    if rect.collidepoint(event.pos) and name != current_solid_name:
                        load_solid(name)
                        break

    angle_x += ROTATION_SPEED
    angle_y += ROTATION_SPEED
    angle_z += ROTATION_SPEED

    rotated_vertices = []
    for x, y, z in vertices:
        y_rot = y * math.cos(angle_x) – z * math.sin(angle_x)
        z_rot = y * math.sin(angle_x) + z * math.cos(angle_x)
        x_rot = x * math.cos(angle_y) – z_rot * math.sin(angle_y)
        z_final = x * math.sin(angle_y) + z_rot * math.cos(angle_y)
        x_final = x_rot * math.cos(angle_z) – y_rot * math.sin(angle_z)
        y_final = x_rot * math.sin(angle_z) + y_rot * math.cos(angle_z)
        rotated_vertices.append((x_final, y_final, z_final))

    projected_vertices = []
    for x, y, z in rotated_vertices:
        distance = 5
        scale = distance / (distance – z / 400)
        proj_x = int(x * scale + (WIDTH + MENU_WIDTH) / 2)
        proj_y = int(y * scale + HEIGHT / 2)
        projected_vertices.append((proj_x, proj_y))

    screen.fill(BACKGROUND_COLOR)

    if projected_vertices:
        # — MODIFIED DRAWING LOGIC FOR WIREFRAME —
        for face in faces:
            points = [projected_vertices[i] for i in face]
            # Draw only the outline of the polygon
            pygame.draw.polygon(screen, LINE_COLOR, points, 1)

    pygame.draw.rect(screen, MENU_BACKGROUND_COLOR, (0, 0, MENU_WIDTH, HEIGHT))
    for name, rect in menu_rects.items():
        color = MENU_HIGHLIGHT_COLOR if name == current_solid_name else MENU_TEXT_COLOR
        text_surf = MENU_FONT.render(name, True, color)
        screen.blit(text_surf, rect)

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

I’m visiting a British seaside town called Margate. There’s a location here called ‘Shell Grotto’. In the 1800s, a landowner uncovered an ancient walkway and altar built underground and covered in thousands of seashells – and nobody knows why. What I’m saying is, prepare for the coming of Cthulu.

Freaky tree on the roanoke river

Carved face in the tree
Closeup on tree face

They say if you walk the banks of the Roanoke near Salem after sundown, best keep your eyes straight ahead and your feet moving. The river twists through those woods quiet as a whisper, and sometimes the quiet is watching back.

I found it in daylight, a tree with a face carved deep into the trunk. Heavy eyes, a frown that sank down like roots. Looked man-made at first, but the longer I stood there the more it felt alive. The cracks in the wood breathed. The shadows under the eyes shifted with no wind.

Old mountain tales say the Roanoke has its watchers. Spirits bound in bark, listening for names carried on the current. Folks claim if you speak too loud near them, the trees remember your voice, and call it back to you years later when you are alone in the hollow.

I didn’t linger. Just tipped my head in respect, the way you’d nod to a grave or a passing crow, and kept to the trail.

Along the river, even in daylight, you can feel the mountains breathing, and sometimes the trees breathe back.

Tic tac toe python test

#!/usr/bin/env python3
“””
Tic-Tac-Toe with simple reinforcement learning (Monte Carlo control)
– Runs in a terminal (works in Pydroid on Android)
– Can train by self-play, play human vs AI, or AI vs AI
– Learns state-action values and improves over time
– Save/Load the learned policy to/from JSON

How it learns (short version):
We record the sequence of (state, action, player) for a game. At the end:
    winner’s actions get +1, loser’s actions get -1, draws get 0
We update a value table Q[(state, player)][action] by incremental averaging.
Policy is epsilon-greedy w.r.t. Q, so it explores a bit while learning.
“””

import json
import os
import random
from collections import defaultdict
from typing import Dict, List, Tuple

# =========================
# Game mechanics
# =========================

EMPTY = ” “
PLAYERS = (“X”, “O”)
WIN_LINES = [
    (0, 1, 2), (3, 4, 5), (6, 7, 8),  # rows
    (0, 3, 6), (1, 4, 7), (2, 5, 8),  # cols
    (0, 4, 8), (2, 4, 6)              # diagonals
]

Board = List[str]
State = str  # 9-char string of ‘X’, ‘O’, or ‘ ‘
Action = int  # index 0..8
QKey = Tuple[State, str]  # (state, current_player)

def new_board() -> Board:
    return [EMPTY] * 9

def board_to_state(board: Board) -> State:
    return “”.join(board)

def legal_actions(board: Board) -> List[Action]:
    return [i for i, c in enumerate(board) if c == EMPTY]

def check_winner(board: Board) -> str:
    for a, b, c in WIN_LINES:
        if board[a] != EMPTY and board[a] == board[b] == board[c]:
            return board[a]
    if EMPTY not in board:
        return “DRAW”
    return “”  # game continues

def print_board(board: Board) -> None:
    b = [c if c != EMPTY else str(i+1) for i, c in enumerate(board)]
    rows = [f” {b[0]} | {b[1]} | {b[2]}”, f” {b[3]} | {b[4]} | {b[5]}”, f” {b[6]} | {b[7]} | {b[8]}”]
    print(“\n” + “\n———–\n”.join(rows) + “\n”)

# =========================
# RL bits (First-Visit Monte Carlo control)
# =========================

class MonteCarloAgent:
    def __init__(self, epsilon: float = 0.1):
        self.epsilon = float(epsilon)
        # Q maps (state, player) -> vector of 9 action values
        self.Q: Dict[QKey, List[float]] = defaultdict(lambda: [0.0]*9)
        # N maps (state, player, action) -> visit count for incremental mean
        self.N: Dict[Tuple[State, str, Action], int] = defaultdict(int)

    def policy(self, board: Board, player: str) -> Action:
        acts = legal_actions(board)
        if not acts:
            return -1
        if random.random() < self.epsilon:
            return random.choice(acts)
        state = board_to_state(board)
        qvals = self.Q[(state, player)]
        # choose best legal; tie-break randomly among maxima
        best_val = max(qvals[a] for a in acts)
        best_actions = [a for a in acts if qvals[a] == best_val]
        return random.choice(best_actions)

    def episode(self, starting_player: str = “X”, show: bool = False) -> str:
        “””Play one game between two copies of this agent (self-play).
        Returns the result: ‘X’, ‘O’, or ‘DRAW’.”””
        board = new_board()
        current = starting_player
        # history of (state, player, action)
        trajectory: List[Tuple[State, str, Action]] = []

        while True:
            action = self.policy(board, current)
            if action == -1:
                # no legal moves (shouldn’t happen)
                result = “DRAW”
                break
            # record state before taking action
            s = board_to_state(board)
            trajectory.append((s, current, action))
            # apply move
            board[action] = current
            outcome = check_winner(board)
            if show:
                print_board(board)
            if outcome == “X” or outcome == “O”:
                result = outcome
                break
            if outcome == “DRAW”:
                result = “DRAW”
                break
            # switch player
            current = “O” if current == “X” else “X”

        # Assign returns
        if result == “DRAW”:
            G = {“X”: 0.0, “O”: 0.0}
        else:
            G = {“X”: 1.0 if result == “X” else -1.0,
                 “O”: 1.0 if result == “O” else -1.0}

        # First-visit MC update
        seen = set()
        for s, p, a in trajectory:
            key = (s, p, a)
            if key in seen:
                continue
            seen.add(key)
            qkey = (s, p)
            self.N[(s, p, a)] += 1
            n = self.N[(s, p, a)]
            old = self.Q[qkey][a]
            target = G[p]
            self.Q[qkey][a] = old + (target – old) / n
        return result

    def choose_move(self, board: Board, player: str, greedy: bool = True) -> Action:
        acts = legal_actions(board)
        if not acts:
            return -1
        state = board_to_state(board)
        qvals = self.Q[(state, player)]
        if greedy:
            best_val = max(qvals[a] for a in acts)
            best_actions = [a for a in acts if qvals[a] == best_val]
            return random.choice(best_actions)
        else:
            return self.policy(board, player)

    # ———- persistence ———-
    def save(self, path: str):
        data = {f”{k[0]}|{k[1]}”: v for k, v in self.Q.items()}
        with open(path, “w”, encoding=”utf-8″) as f:
            json.dump({“epsilon”: self.epsilon, “Q”: data}, f)
        print(f”Saved model to {path} ({len(self.Q)} states)”)

    def load(self, path: str):
        if not os.path.exists(path):
            print(f”No such file: {path}”)
            return
        with open(path, “r”, encoding=”utf-8″) as f:
            blob = json.load(f)
        self.epsilon = float(blob.get(“epsilon”, 0.1))
        rawQ = blob.get(“Q”, {})
        self.Q = defaultdict(lambda: [0.0]*9)
        for k, v in rawQ.items():
            state, player = k.split(“|”)
            vec = [float(x) for x in v]
            if len(vec) != 9:
                vec = (vec + [0.0]*9)[:9]
            self.Q[(state, player)] = vec
        print(f”Loaded model from {path} ({len(self.Q)} states), epsilon={self.epsilon}”)

# =========================
# Human interaction
# =========================

MODEL_PATH = “tictactoe_q.json”

def human_turn(board: Board, player: str) -> None:
    while True:
        try:
            move = input(f”Your move ({player}). Enter 1-9: “).strip()
            idx = int(move) – 1
            if idx < 0 or idx > 8:
                raise ValueError
            if board[idx] != EMPTY:
                print(“That spot is taken. Try again.”)
                continue
            board[idx] = player
            return
        except ValueError:
            print(“Please type a number 1-9 corresponding to the board position.”)

def ai_turn(board: Board, player: str, agent: MonteCarloAgent, greedy: bool = True) -> None:
    a = agent.choose_move(board, player, greedy=greedy)
    if a == -1:
        return
    board[a] = player

def play_human_vs_ai(agent: MonteCarloAgent):
    print(“\n=== Human vs AI ===”)
    while True:
        choice = input(“Do you want to be X (first) or O (second)? [X/O]: “).strip().upper()
        if choice in (“X”, “O”):
            human = choice
            ai = “O” if human == “X” else “X”
            break
        print(“Please answer X or O.”)

    greedy = input(“Should the AI play greedily (y) or allow exploration (n)? [y/n]: “).strip().lower() != ‘n’

    board = new_board()
    current = “X”
    print_board(board)

    while True:
        if current == human:
            human_turn(board, human)
        else:
            ai_turn(board, ai, agent, greedy=greedy)
            print(“AI moves:”)
        print_board(board)
        outcome = check_winner(board)
        if outcome in (“X”, “O”):
            print(f”{outcome} wins!” + (” (You win!)” if outcome == human else ” (AI wins!)”))
            break
        if outcome == “DRAW”:
            print(“It’s a draw.”)
            break
        current = “O” if current == “X” else “X”

def watch_ai_vs_ai(agent: MonteCarloAgent, games: int = 1, greedy: bool = True):
    print(“\n=== AI vs AI ===”)
    for g in range(1, games+1):
        print(f”Game {g}:”)
        result = agent.episode(starting_player=”X”, show=True)
        if result == “DRAW”:
            print(“Result: draw\n”)
        else:
            print(f”Result: {result} wins\n”)

def train_self_play(agent: MonteCarloAgent, episodes: int = 10000, report_every: int = 1000):
    print(f”Training for {episodes} self-play games (epsilon={agent.epsilon})…”)
    w = {“X”: 0, “O”: 0, “DRAW”: 0}
    for i in range(1, episodes+1):
        # alternate starting player to avoid bias
        starter = “X” if i % 2 else “O”
        result = agent.episode(starting_player=starter, show=False)
        w[result] += 1
        if report_every and i % report_every == 0:
            total = i
            wx, wo, d = w[“X”], w[“O”], w[“DRAW”]
            print(f”  After {total:6d}: X={wx} O={wo} Draw={d} | states learned={len(agent.Q)}”)
    print(“Done.”)

# =========================
# Menu / main
# =========================

def main():
    agent = MonteCarloAgent(epsilon=0.1)
    if os.path.exists(MODEL_PATH):
        try:
            agent.load(MODEL_PATH)
        except Exception as e:
            print(f”(Could not auto-load model: {e})”)

    while True:
        print(“””
==============================
Tic-Tac-Toe RL (console)
==============================
1) Train by self-play
2) Play Human vs AI
3) Watch AI vs AI
4) Set exploration epsilon
5) Save model
6) Load model
7) Reset model
0) Exit
“””)
        choice = input(“Select an option: “).strip()

        if choice == “1”:
            try:
                n = int(input(“How many self-play games? (e.g., 5000): “).strip())
            except ValueError:
                print(“Please enter a number.”)
                continue
            report = max(1000, n // 10)
            train_self_play(agent, episodes=n, report_every=report)
        elif choice == “2”:
            play_human_vs_ai(agent)
        elif choice == “3”:
            try:
                g = int(input(“How many games to show? “).strip())
            except ValueError:
                g = 1
            greedy = input(“Play greedily (y) or with exploration (n)? [y/n]: “).strip().lower() != ‘n’
            watch_ai_vs_ai(agent, games=g, greedy=greedy)
        elif choice == “4”:
            try:
                e = float(input(“Set epsilon (0 = greedy, 0.1 default, 1 = random): “).strip())
                e = min(max(e, 0.0), 1.0)
                agent.epsilon = e
                print(f”epsilon set to {agent.epsilon}”)
            except ValueError:
                print(“Please enter a number (e.g., 0.1)”)
        elif choice == “5”:
            path = input(f”Save path [{MODEL_PATH}]: “).strip() or MODEL_PATH
            agent.save(path)
        elif choice == “6”:
            path = input(f”Load path [{MODEL_PATH}]: “).strip() or MODEL_PATH
            agent.load(path)
        elif choice == “7”:
            agent = MonteCarloAgent(epsilon=agent.epsilon)
            print(“Model reset. (Learning starts fresh.)”)
        elif choice == “0”:
            print(“Goodbye!”)
            break
        else:
            print(“Unknown option. Please choose from the menu.”)

if __name__ == “__main__”:
    main()

Day 20654

Afternoon carried me and my companions into Evie’s Bakery, quiet hum of ovens and glass cases shining with sugar. Amanda, smiling and steady, steered us through the tasting like she’d been waiting just for us.

Better Than Sex cake first. Devil’s food rich and shadow dark, chocolate chips hidden in the crumb. Whipped white frosting smoothed over, tangled with chocolate and caramel. Each forkful heavy with sweetness, melt and bite together, little bursts of joy.

Then sunshine cake. Yellow crumb, tender as a cloud, holding its weight under a plate of milk chocolate icing. The balance of bright and sweet, golden light under a darker crown, lifted everything a little higher.

We lingered, fork tapping the empty plate, warm air rising from the ovens, downstairs. We put an order in for both full cakes for an upcoming birthday party later this month.

When we stepped back outside, the sidewalk carried its own invitation. Hopscotch chalked in pastel squares, the word dance scrawled in the final box. Sunlight caught it just so, and for a moment it felt like the cakes had followed us out, turning the street into something just as sweet.

#EviesBakery #CakeTasting #BetterThanSexCake #SunshineCake #SweetLife #ChalkHopscotch #DanceAtTheEnd


Day 20,653

Bigfoot on his recumbent bike

The Y waited in the gray drizzle this morning, doors sliding open like a slow inhale. I went alone, bag on shoulder, carrying towel, lock, and swimsuit. The lobby carried its usual mix of coffee and chlorine, a scent that feels like both welcome and warning, as if the building wants to remind you that effort and comfort live side by side here.

First, I settled onto a recumbent bike. Low seat, pedals forward, the kind of machine that lets you lean back a little, legs moving like steady oars. The screen glowed with numbers I barely watched. Beyond the fogged windows the street blurred, people passing like shadows in watercolor. The bike seemed content to carry me through the minutes, humming beneath me as though pleased to share its rhythm.

Then the pool. Ninety degrees, five feet deep, a body of water that felt more like a living thing than a facility feature. Stepping in was like being welcomed into its arms, warm against the skin, the depth just enough to hold me without ever letting me disappear. Plenty of space, no rush, no crowding, the water stretching wide and patient. Each lap was less about distance and more about drifting through the gentle embrace, lights above shimmering like constellations stirred by the smallest stroke.

I briefly lingered at the edge after swimming, towel wrapped tight absorbing stray drops before I headed back to the changing area, listening to the pool breathe under the echoes of children’s laughter at the far end. The humid air wrapped itself around me, heavy but comforting, like the last word in a quiet conversation.

When I stepped outside again, drizzle cooled my skin and hair. I felt as though the pool had pressed its warmth into me, a secret gift from the water, carried out into the gray day like a blessing.

#roanokeva #salemva #ymca

The Painted Pig

They call him just the pig, though he’s more than that. A squat figure of concrete planted on West Main, round-bellied and silent, carrying the weight of Salem’s years in paint and shadow.

The elders whisper that when Henry’s barbecue joint closed, the town grew restless. Windows darkened, smoke gone from the pit, but people felt the loss in their bones. Something lingered, wanting a place to live on. So the pig stayed. And with each fresh coat of paint, he learned to listen.

Children mark his hide with birthday wishes and bright doodles, never knowing the stone soaks up their voices. Lovers scrawl their names, and months later, when the paint fades, their romance too crumbles like chipped acrylic. Preachers leave blessings, and for a season the air seems lighter. Protesters splash slogans in the night, and by dawn the town feels braced for change. What is written on him has a way of echoing back.

Some say if you pass him after midnight, when the street is empty and the lamps buzz with moths, you’ll hear him shifting his trotters against the pavement. Just enough to shake loose the old stories, to make room for the new. His eyes — blank and painted over a thousand times — are never the same color twice, yet they follow. Always watching.

It’s said Salem has been spared worse storms than its neighbors, spared fires that could have swept whole blocks, because the pig takes it on himself. He drinks down the town’s misfortune like rain. But he demands attention in return. If the paint ever stops, if people forget to mark him, his belly will grow heavy with unshed stories, and the luck of Salem will sour.

So the brushes keep coming. Small hands, weary hands, bold hands with spray cans in the dark. The pig wears it all, a patchwork shroud of human hope and folly. Protector, trickster, omen.

And he will not leave. Not until Salem does.

#salemva #paintedpig #appalachianfolklore #concretespirit #roanokeva

Brush mtn draft 5

The Mountain That Keeps

(A Brush Mountain Tale)

There’s a ridge above Catawba folks don’t linger on. Brush Mountain, long and dark, the kind of rise that carries a weight in its bones. The old timers say a mountain is like a hound… feed it once, and it’ll never stop coming back. But when you feed it blood, you’ve made a pact you can’t unmake.

In May of 1971, a small plane cut through the clouds over that ridge. In it was Audie Murphy, soldier, actor, hero; a man who carried more medals than his coat could bear, a man who walked through fire overseas and came out breathing when others did not. Folks liked to say he had death by the collar. But on that fog-thick morning, Brush Mountain decided otherwise. The plane hit the slope hard, tore open trees, and burned hot enough to scorch the stones. All aboard were gone in a heartbeat.

The sheriff’s men hauled what they could out, but the mountain kept the rest. Kept the smoke, kept the screams, kept the shadow of it all.



Porch Talk

Years later, if you sat on Cal Dempsey’s porch of an evening, he’d tell it plain.

“Brush Mountain ain’t right,” he’d say, rocking slow, his lantern throwing shadows across the boards. “That ridge pulled Murphy down same as a snapping turtle pulls under a duck. Weren’t no accident. Mountain drew in breath, filled the air with fog, and swallowed him whole.”

Somebody would laugh, usually a young’un visiting from town. Cal would just spit and shake his head. “You think I’m telling jokes? Ask the hunter heard an engine coughin’ overhead on a clear night, no plane in sight. Ask the woman seen a row of soldiers in the mist, marchin’ quiet along the slope, uniforms gray as ashes, and then*poof* gone into the brush. Ask the boys who dared each other to sleep by the memorial stone. Not one lasted till midnight. Said the ground was too restless, like it wanted to roll over under ‘em.”



The Memorial

They put up a granite block where the plane went down, carved a bronze plaque on it so strangers would know the tale. But the locals will tell you the real memorial is the hush in the clearing. Birds fall silent, cicadas choke off mid-song, even the trees stop creaking. Step into that stillness, and you’ll feel the mountain watching.

Coins and trinkets gather at the base of the stone. Pennies, nickels, army patches, toy soldiers, even a faded pack of Lucky Strikes once. They aren’t offerings to Audie Murphy himself. No, those are gifts to the mountain, bargains struck so you’ll walk back down safe.

There’s a saying in the Blue Ridge: A sudden death makes a shadow that never fades. Brush Mountain is fat with such shadows, and Murphy’s is the heaviest.



My Walk

I climbed it once, curious or foolish. The trail was quiet, gravel underfoot, trees crowding close. When I reached the stone, the air thickened like syrup. No birds. No insects. Just a silence heavy enough to press against my chest.

I set a coin down. My hand shook doing it. And I swear before heaven that a figure stood just beyond the tree line… cap low, hand resting on the granite. His outline wavered, like smoke. His eyes were hollows, watching. Then the wind moved and he was gone, or folded deeper into the mountain’s skin.

The silence broke in a rush. Cicadas screamed. A crow barked. I turned and left fast as I dared, not looking back until the trail bent away.



The Warning

Cal told it best the last time I saw him, pipe glowing in his teeth.

“Folks think that memorial’s a monument. But what it really is, is a doorstop. Keeps the mountain from swallowin’ the rest of us whole. You don’t mock it. You don’t linger after dark. And you sure as hell don’t walk up there without bringin’ payment. Remember; what the mountain takes, it never gives back. Not in this world, nor the next.”

And the lantern would flicker, and the shadows would stretch long, and you’d know in your bones that every word he spoke was true.

Lil Brushy legend draft 4

“Little Brushy Mountain ain’t right,” old Cal used to say, spitting tobacco into the dust by his boots. “Never has been. Ridge like that, it keeps what it takes. You walk up there, best remember to mind your manners.”

He’d lean forward then, voice dropping low. “You heard about Audie Murphy, ain’t you? War hero, made it through more firefights than you got fingers, walked away from hell in Europe without so much as a limp. They say the man had death’s own handshake but never let it stick. Then in seventy-one, him and a few others was flying over, and that mountain pulled ‘em down. Fog come sudden, thicker’n buttermilk, and the next thing, metal screaming and fire blooming. Folks said you could smell the smoke all the way in Catawba. Not a one survived. That’s the way Little Brushy wanted it.”

Old timers claim the fog that day wasn’t weather at all. “That was the mountain drawing breath,” Cal would say, eyes narrowing at the tree line. “Pulling the plane into its lungs.”

And then he’d rattle off the stories. A hunter hearing an engine sputtering overhead on a still night, nothing in the sky. A woman walking the trail and seeing soldiers in the mist, marching slow, their boots never touching the ground, fading right into the brush. Kids daring each other to sleep by the monument but running home before dusk because the woods were too quiet, too thick.

Cal always spat again after telling that. “There’s a sayin’ here. Sudden death makes a shadow that never fades. Brush Mountain’s belly’s full of ‘em. And Murphy’s shadow, it’s the heaviest.”

I asked him once why folks left coins and trinkets by the stone. He tapped the brim of his hat like it was obvious. “You don’t bring the mountain a gift, the mountain might take somethin’ else. Could be your luck, could be your way back down. Folks don’t play dice with ridges that’ve tasted blood.”

I went up there myself, once, just to see. Walked the trail till the stone rose out the clearing, bronze glinting dull in the evening light. Left a coin at the base, though my hand shook when I did it. The woods pressed close, thick and watching. Air heavy as iron in my mouth. For a moment I swear I saw a figure by the trees, cap pulled low, one hand resting on the stone. Then the wind groaned through the branches and he was gone, or maybe just deeper in.

Cal had one more thing he’d say before he’d rock back and light his pipe. “That ridge don’t forget. Don’t forgive neither. You go up there, remember, the mountain is awake. What it takes, it never gives back.”

And the lantern light would flicker, and the night insects would start up again, and you’d know he wasn’t just telling tales. Not all the way.

Welcome to my wall scrawls.