Robots/Julia
Julia
Uses the Gtk library.
<lang julia>using Gtk, Colors, Cairo, Graphics
const fontpointsize = 10 const mapwidth = 900 const mapheight = 700 const leveldim = div(mapwidth, fontpointsize) const windowmaxx = div(mapheight, fontpointsize) const windowmaxy = leveldim
win = GtkWindow("Robots Game (H for Help)", mapwidth, mapheight) |> (GtkFrame() |> (vbox = GtkBox(:v))) set_gtk_property!(vbox, :expand, true) can = GtkCanvas(div(mapwidth, 3), mapheight) push!(vbox, can)
const playerchar, robotchar, hazardchar, wallchar, spacechar = '@', '+', '\u2623', '\u2593', ' ' const itemcolors = Dict{Char, Colorant}('@' => colorant"white", ' ' => colorant"black",
'\u2623' => colorant"gold", '+' => colorant"red", '\u2593' => colorant"silver")
const debrisprobability, debrisdiameter, maxrobots, gravechar = 0.005, 6, 10, '\u271d' const gameover = [false]
const grid = fill(spacechar, windowmaxx, windowmaxy)
@guarded draw(can) do widget
ctx = getgc(can) select_font_face(ctx, "Courier", Cairo.FONT_SLANT_NORMAL, Cairo.FONT_WEIGHT_BOLD) set_font_size(ctx, fontpointsize) workcolor = colorant"black" set_source_rgb(ctx, 0.2, 0.2, 0.2) rectangle(ctx, 0, 0, mapwidth, mapheight) fill(ctx) color = colorant"white" set_source(ctx, color) linelen = size(grid)[2] workbuf = Char[] for i in 1:size(grid)[1] move_to(ctx, 0, i * fontpointsize) lastcharprinted = '\x01' for j in 1:linelen ch = grid[i, j] if j == 1 lastcharprinted = ch elseif ch != lastcharprinted show_text(ctx, String(workbuf)) empty!(workbuf) end if haskey(itemcolors, ch) && itemcolors[ch] != color color = itemcolors[ch] set_source(ctx, color) end push!(workbuf, ch) if j == linelen show_text(ctx, String(workbuf)) empty!(workbuf) end end end
end
struct Point
x::Int y::Int
end
randomlocation() = Point(rand(2:windowmaxx-1), rand(2:windowmaxy))
function randomdiameterfill(n, center, ch)
d = rand(1:n) surround = [Point(i + center.x, j + center.y) for i in -d:d, j in -d:d] for p in surround if p.x > 1 && p.x < windowmaxx -1 && p.y > 1 && p.y < windowmaxy -1 if rand() * d > sqrt((center.x - p.x)^2 + (center.y - p.y)^2) grid[p.x, p.y] = ch end end end
end
function randomemptypoint()
for i in 1:100000 pt = randomlocation() if grid[pt.x, pt.y] == spacechar return pt end end throw("Cannot find an empty point in the grid")
end
mutable struct Player
location::Point movenumber::Int lastteleport::Int Player() = new(randomemptypoint(), 1, 0)
end
mutable struct Robot
location::Point active::Bool
end
function setupgrid()
x1, y1, x2, y2, robots = 1, 1, windowmaxx, windowmaxy, Robot[] grid[x1:x2, y1:y2] .= ' ' grid[x1:x2, y1] .= wallchar grid[x1:x2, y2] .= wallchar grid[x1, y1:y2] .= wallchar grid[x2, y1:y2] .= wallchar for x in x1:x2, y in y1:y2 if rand() < debrisprobability randomdiameterfill(debrisdiameter, Point(x, y), hazardchar) end end for _ in 1:maxrobots p = randomemptypoint() grid[p.x, p.y] = robotchar push!(robots, Robot(p, true)) end return Player(), robots
end
function updategrid!(player)
grid[player.location.x, player.location.y] = playerchar Gtk.showall(win) draw(can) Gtk.show(can)
end
function help(player)
info_dialog("W up, S down, A left, D right, Spacebar teleport (every 12 moves).\n" * " Avoid Robots and Hazards! Good Luck!", win)
end
playerwins(p) = warn_dialog("You have WON the game!\nTotal moves: $(p.movenumber)", win) playerloses(p) = warn_dialog("You have lost the game.\nTotal moves: $(p.movenumber)", win)
function destroyrobot!(robots, x, y)
if grid[x, y] == robotchar grid[x, y] = hazardchar for (i, robot) in enumerate(robots) if robot.location.x == x && robot.location.y == y robots[i].active = false break end end end
end
function moverobot!(robots, robot, dx, dy, player)
(dx == 0 && dy == 0) && return false p = Point(robot.location.x + dx, robot.location.y + dy) if grid[p.x, p.y] == wallchar return false elseif grid[p.x, p.y] == spacechar # robot moves a space grid[robot.location.x, robot.location.y] = spacechar grid[p.x, p.y] = robotchar robot.location = Point(p.x, p.y) return true elseif grid[p.x, p.y] == robotchar # robots collide destroyrobot!(robots, robot.location.x, robot.location.y) destroyrobot!(robots, p.x, p.y) elseif grid[p.x, p.y] == hazardchar # robot hits hazard destroyrobot!(robots, robot.location.x, robot.location.y) elseif grid[p.x, p.y] == playerchar # robot hits player grid[p.x, p.y] = gravechar gameover[1] = true playerloses(player) end if all(r -> !r.active, robots) gameover[1] = true updategrid!(player) playerwins(player) end return false
end
function robotsmove!(robots, player)
for robot in robots if robot.active dx = player.location.x - robot.location.x dy = player.location.y - robot.location.y xmove = dx > 0 ? 1 : dx == 0 ? 0 : -1 ymove = dy > 0 ? 1 : dy == 0 ? 0 : -1 if !moverobot!(robots, robot, xmove, ymove, player) moverobot!(robots, robot, rand([-1, 0, 1]), rand([-1, 0, 1]), player) end else grid[robot.location.x, robot.location.y] = hazardchar end end
end
function playerteleport(player)
if player.lastteleport < player.movenumber p = randomemptypoint() grid[player.location.x, player.location.y] = spacechar grid[p.x, p.y] = playerchar player.location = p player.movenumber += 1 player.lastteleport = player.movenumber + 12 updategrid!(player) end
end
function playermove(player, dx, dy)
goalp = Point(player.location.x + dx, player.location.y + dy) if grid[goalp.x, goalp.y] != wallchar if grid[goalp.x, goalp.y] == hazardchar || grid[goalp.x, goalp.y] == robotchar grid[player.location.x, player.location.y] = gravechar gameover[1] = true updategrid!(player) playerloses(player) else grid[player.location.x, player.location.y] = spacechar player.location = Point(goalp.x, goalp.y) grid[goalp.x, goalp.y] = playerchar end end player.movenumber += 1
end playerN(player) = playermove(player, -1, 0) playerW(player) = playermove(player, 0, -1) playerS(player) = playermove(player, 1, 0) playerE(player) = playermove(player, 0, 1)
const usercommands = Dict("W" => playerN, "S" => playerS, "D" => playerE, "A" => playerW,
" " => playerteleport, "H" => help)
const inputchan = Channel{String}(1000) kbinput(w, event) = (push!(inputchan, string(Char(event.keyval))); 1) const inputhid = signal_connect(kbinput, win, "key-press-event") getinput(choices) = while true if (c = uppercase(take!(inputchan))) in choices return c end; end
function rungame()
player, robots = setupgrid() while !gameover[1] robotsmove!(robots, player) updategrid!(player) choice = getinput(keys(usercommands)) usercommands[choice](player) end
end
rungame() </lang>