Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local version = "1.0"
- local config = {
- gridWidth = 150,
- gridHeight = 100,
- updateInterval = 0.1,
- maxZoom = 4,
- historySize = 20,
- patterns = {
- glider = {{0,1,0},{0,0,1},{1,1,1}},
- blinker = {{1},{1},{1}},
- pulsar = {
- {0,0,1,1,1,0,0,0,1,1,1,0,0},
- {0,0,0,0,0,0,0,0,0,0,0,0,0},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {0,0,1,1,1,0,0,0,1,1,1,0,0},
- {0,0,0,0,0,0,0,0,0,0,0,0,0},
- {0,0,1,1,1,0,0,0,1,1,1,0,0},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {1,0,0,0,0,1,0,1,0,0,0,0,1},
- {0,0,0,0,0,0,0,0,0,0,0,0,0},
- {0,0,1,1,1,0,0,0,1,1,1,0,0}
- },
- spaceship = {{1,0,0,1,0},{0,0,0,0,1},{1,0,0,0,1},{0,1,1,1,1}}
- }
- }
- config.screenWidth, config.screenHeight = term.getSize()
- local state = {
- grid = {},
- scrollX = 0,
- scrollY = 0,
- paused = true,
- automatic = false,
- generation = 0,
- population = 0,
- mode = "conway",
- zoomLevel = 1,
- history = {},
- selectedPattern = "glider"
- }
- for y = 1, config.gridHeight do
- state.grid[y] = {}
- for x = 1, config.gridWidth do
- state.grid[y][x] = 0
- end
- end
- local function deepCopy(orig)
- local orig_type = type(orig)
- local copy
- if orig_type == 'table' then
- copy = {}
- for orig_key, orig_value in next, orig, nil do
- copy[deepCopy(orig_key)] = deepCopy(orig_value)
- end
- setmetatable(copy, deepCopy(getmetatable(orig)))
- else
- copy = orig
- end
- return copy
- end
- local function countNeighbors(x, y)
- local count = 0
- for dy = -1, 1 do
- for dx = -1, 1 do
- if dx ~= 0 or dy ~= 0 then
- local nx, ny = (x + dx - 1) % config.gridWidth + 1, (y + dy - 1) % config.gridHeight + 1
- count = count + state.grid[ny][nx]
- end
- end
- end
- return count
- end
- local function updateGrid()
- local newGrid, newPopulation = {}, 0
- for y = 1, config.gridHeight do
- newGrid[y] = {}
- for x = 1, config.gridWidth do
- local neighbors = countNeighbors(x, y)
- local cell = state.grid[y][x]
- local newCell = 0
- if state.mode == "conway" then
- newCell = ((cell == 1 and (neighbors == 2 or neighbors == 3)) or (cell == 0 and neighbors == 3)) and 1 or 0
- elseif state.mode == "highlife" then
- newCell = ((cell == 1 and (neighbors == 2 or neighbors == 3)) or (cell == 0 and (neighbors == 3 or neighbors == 6))) and 1 or 0
- elseif state.mode == "daynight" then
- newCell = ((cell == 1 and (neighbors == 3 or neighbors == 4 or neighbors == 6 or neighbors == 7 or neighbors == 8)) or
- (cell == 0 and (neighbors == 3 or neighbors == 6 or neighbors == 7 or neighbors == 8))) and 1 or 0
- end
- newGrid[y][x] = newCell
- newPopulation = newPopulation + newCell
- end
- end
- table.insert(state.history, 1, deepCopy(state.grid))
- if #state.history > config.historySize then table.remove(state.history) end
- state.grid = newGrid
- state.generation = state.generation + 1
- state.population = newPopulation
- end
- local function drawCell(x, y, alive)
- local char = alive and "\127" or " "
- local fg = alive and colors.lime or colors.black
- local bg = alive and colors.green or colors.gray
- return char, fg, bg
- end
- local function drawGrid()
- local buffer = {}
- for y = 1, config.screenHeight - 3 do
- buffer[y] = {text = "", fg = {}, bg = {}}
- for x = 1, config.screenWidth do
- local gridX = math.floor((x - 1 + state.scrollX) / state.zoomLevel) + 1
- local gridY = math.floor((y - 1 + state.scrollY) / state.zoomLevel) + 1
- if gridX >= 1 and gridX <= config.gridWidth and gridY >= 1 and gridY <= config.gridHeight then
- local char, fg, bg = drawCell(gridX, gridY, state.grid[gridY][gridX] == 1)
- buffer[y].text = buffer[y].text .. char
- buffer[y].fg[x] = fg
- buffer[y].bg[x] = bg
- else
- buffer[y].text = buffer[y].text .. " "
- buffer[y].fg[x] = colors.black
- buffer[y].bg[x] = colors.gray
- end
- end
- end
- for y = 1, config.screenHeight - 3 do
- for x = 1, config.screenWidth do
- term.setCursorPos(x, y)
- term.setTextColor(buffer[y].fg[x])
- term.setBackgroundColor(buffer[y].bg[x])
- term.write(buffer[y].text:sub(x,x))
- end
- end
- local status = state.paused and "Paused" or (state.automatic and "Auto" or "Running")
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.yellow)
- term.setCursorPos(1, config.screenHeight - 2)
- term.write(string.format("CC-Conway v%s | Mode: %s | Gen: %d | Pop: %d | Zoom: %d",
- version, state.mode, state.generation, state.population, state.zoomLevel))
- term.setCursorPos(1, config.screenHeight - 1)
- term.setTextColor(colors.cyan)
- term.write(string.format("Status: %s | Pattern: %s", status, state.selectedPattern))
- term.setCursorPos(1, config.screenHeight)
- term.setTextColor(colors.white)
- term.write("Press H for Help")
- end
- local function placePattern(patternName, x, y)
- local pattern = config.patterns[patternName]
- if not pattern then return end
- for dy = 1, #pattern do
- if type(pattern[dy]) ~= "table" then return end
- for dx = 1, #pattern[dy] do
- local gx, gy = x + dx - 1, y + dy - 1
- if gx >= 1 and gx <= config.gridWidth and gy >= 1 and gy <= config.gridHeight then
- state.grid[gy][gx] = pattern[dy][dx]
- end
- end
- end
- end
- local function handleMouse(button, x, y)
- if y <= config.screenHeight - 3 then
- local gridX = math.floor((x - 1 + state.scrollX) / state.zoomLevel) + 1
- local gridY = math.floor((y - 1 + state.scrollY) / state.zoomLevel) + 1
- if gridX >= 1 and gridX <= config.gridWidth and gridY >= 1 and gridY <= config.gridHeight then
- if button == 1 then
- state.grid[gridY][gridX] = 1 - state.grid[gridY][gridX]
- elseif button == 2 then
- placePattern(state.selectedPattern, gridX, gridY)
- end
- end
- end
- end
- local function showPatternMenu()
- local patterns = {}
- for name, _ in pairs(config.patterns) do
- table.insert(patterns, name)
- end
- table.sort(patterns)
- local function drawMenu()
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- term.setTextColor(colors.yellow)
- print("Select a pattern:")
- for i, name in ipairs(patterns) do
- term.setTextColor(colors.white)
- term.setCursorPos(2, i + 1)
- print(i .. ". " .. name)
- term.setBackgroundColor(colors.gray)
- term.setCursorPos(1, i + 1)
- term.write(" ")
- term.setBackgroundColor(colors.black)
- end
- term.setTextColor(colors.red)
- term.setCursorPos(2, #patterns + 3)
- print("Cancel")
- term.setBackgroundColor(colors.gray)
- term.setCursorPos(1, #patterns + 3)
- term.write(" ")
- term.setBackgroundColor(colors.black)
- end
- drawMenu()
- while true do
- local event, button, x, y = os.pullEvent("mouse_click")
- if button == 1 then
- if y >= 2 and y <= #patterns + 1 and x <= 20 then
- state.selectedPattern = patterns[y - 1]
- return
- elseif y == #patterns + 3 and x <= 8 then
- return
- end
- end
- end
- end
- local function showGuide()
- local guide = {
- {"Q", "Quit the program"},
- {"S", "Step (advance one generation)"},
- {"R", "Reset with random cells"},
- {"M", "Change mode (Conway, HighLife, Day & Night)"},
- {"P", "Select pattern"},
- {"C", "Clear the grid"},
- {"A", "Toggle automatic mode"},
- {"Z", "Zoom in"},
- {"X", "Zoom out"},
- {"U", "Undo last change"},
- {"Left Shift", "Pause/Resume"},
- {"Space", "Pause/Resume"},
- {"Arrow Keys", "Scroll the grid"},
- {"Left Click", "Toggle cell state"},
- {"Right Click", "Place selected pattern"},
- {"H", "Show this help guide"}
- }
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- term.setTextColor(colors.yellow)
- print("CC-Conway Controls:")
- for _, control in ipairs(guide) do
- term.setTextColor(colors.white)
- print(control[1] .. ":")
- term.setTextColor(colors.cyan)
- print(" " .. control[2])
- print()
- end
- term.setTextColor(colors.yellow)
- print("Press any key to return...")
- os.pullEvent("key")
- end
- local function handleKey(key)
- if key == keys.left then
- state.scrollX = math.max(0, state.scrollX - state.zoomLevel)
- elseif key == keys.right then
- state.scrollX = math.min(config.gridWidth * state.zoomLevel - config.screenWidth, state.scrollX + state.zoomLevel)
- elseif key == keys.up then
- state.scrollY = math.max(0, state.scrollY - state.zoomLevel)
- elseif key == keys.down then
- state.scrollY = math.min(config.gridHeight * state.zoomLevel - config.screenHeight + 3, state.scrollY + state.zoomLevel)
- elseif key == keys.space then
- state.paused = not state.paused
- state.automatic = false
- elseif key == keys.s then
- updateGrid()
- elseif key == keys.r then
- state.generation, state.population = 0, 0
- for y = 1, config.gridHeight do
- for x = 1, config.gridWidth do
- state.grid[y][x] = math.random(0, 1)
- state.population = state.population + state.grid[y][x]
- end
- end
- elseif key == keys.m then
- if state.mode == "conway" then state.mode = "highlife"
- elseif state.mode == "highlife" then state.mode = "daynight"
- else state.mode = "conway" end
- elseif key == keys.p then
- state.paused = true
- showPatternMenu()
- os.sleep(0.5)
- elseif key == keys.c then
- for y = 1, config.gridHeight do
- for x = 1, config.gridWidth do
- state.grid[y][x] = 0
- end
- end
- state.generation, state.population = 0, 0
- elseif key == keys.a then
- state.automatic = not state.automatic
- state.paused = false
- elseif key == keys.z then
- if state.zoomLevel < config.maxZoom then
- state.zoomLevel = state.zoomLevel + 1
- end
- elseif key == keys.x then
- if state.zoomLevel > 1 then
- state.zoomLevel = state.zoomLevel - 1
- end
- elseif key == keys.u and #state.history > 0 then
- state.grid = table.remove(state.history, 1)
- state.generation = math.max(0, state.generation - 1)
- elseif key == keys.leftShift then
- state.paused = not state.paused
- state.automatic = false
- elseif key == keys.h then
- showGuide()
- end
- end
- local function mainLoop()
- local lastUpdate = os.clock()
- while true do
- drawGrid()
- local timer = os.startTimer(config.updateInterval)
- while true do
- local event, p1, p2, p3 = os.pullEvent()
- if event == "mouse_click" then
- handleMouse(p1, p2, p3)
- break
- elseif event == "key" then
- if p1 == keys.q then
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- term.setTextColor(colors.yellow)
- print("Thank you for playing CC-Conway!")
- return
- end
- handleKey(p1)
- break
- elseif event == "timer" and p1 == timer then
- if not state.paused or state.automatic then
- updateGrid()
- lastUpdate = os.clock()
- end
- break
- end
- end
- end
- end
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- term.setTextColor(colors.yellow)
- print("Welcome to CC-Conway v" .. version)
- term.setTextColor(colors.lime)
- print("Coded by nonogamer9")
- term.setTextColor(colors.cyan)
- print("Press any key to start...")
- os.pullEvent("key")
- mainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement