Skip to content

Instantly share code, notes, and snippets.

@benjamingorman
Created December 29, 2014 17:56
Show Gist options
  • Save benjamingorman/99877df5c539e867272d to your computer and use it in GitHub Desktop.
Save benjamingorman/99877df5c539e867272d to your computer and use it in GitHub Desktop.
Robot functions for use with botchallenge
from botchallenge import *
import math
from hilbert import Hilbert
from copy import copy
rob = Robot("Normangorman", "europe.botchallenge.net")
print("Connected")
def smart_range(a, b):
if a == b:
return []
elif a < b:
return range(a,b)
else:
return range(a,b,-1)
def sign(x):
if x < 0:
return -1
else:
return 1
def get_loc_path(loc_a, loc_b):
# Enumerate all the points between locations a and b
locs = []
p = loc_a
dx = sign(loc_b.x_coord - loc_a.x_coord)
dy = sign(loc_b.y_coord - loc_a.y_coord)
dz = sign(loc_b.z_coord - loc_a.z_coord)
while p.x_coord != loc_b.x_coord:
p.x_coord += dx
locs.append( copy(p) )
while p.y_coord != loc_b.y_coord:
p.y_coord += dy
locs.append( copy(p) )
while p.z_coord != loc_b.z_coord:
p.z_coord += dz
locs.append( copy(p) )
return locs
def force_goto_loc(r, loc):
print("Forcing path to: ", loc)
r_loc = r.get_location()
locs = get_loc_path(r_loc, loc)
for p in locs:
r_loc = r.get_location()
# print(p)
# The robot was not able to move correctly - something went wrong
if force_move(r, r_loc.direction(p)) == False:
print("ERROR force_goto_loc: force_move returned False")
return
print("Finished moving.")
def safe_goto_loc(r, loc):
print("Safely moving to: ", loc)
locs = get_loc_path(r.get_location(), loc)
next_dir = r.get_location().direction(locs[0])
# Sample the block type, then move to it - mining the block if it is solid
prev_bid = r.get_block_type( next_dir )
force_move(r, next_dir)
for i in range(1, len(locs)):
next_dir = locs[i-1].direction(locs[i])
next_bid = r.get_block_type(next_dir)
# The robot was not able to move correctly - something went wrong
if force_move(r, next_dir) == False:
print("ERROR safe_goto_loc: force_move returned False")
return
# Some blocks don't drop what they are - convert accordingly
if prev_bid == BlockType.GRASS:
prev_bid = BlockType.DIRT
prev_dir = locs[i].direction(locs[i-1])
# Replace the block behind
if r.place(prev_dir, prev_bid) == False:
print("ERROR safe_goto_loc: could not replace block with id: ", prev_bid)
prev_bid = next_bid
print ("Finished moving.")
def goto_owner(r):
safe_goto_loc(r, r.get_owner_location())
def force_move(r, d):
if r.is_block_solid(d):
r.mine(d)
# it must be bedrock
if r.is_block_solid(d):
print("ERROR force_move: encountered bedrock")
return False
# else the block is transparent, so move to it
else:
r.move(d)
return True
def forward(r, n):
for _ in range(n):
force_move(r, Dir.FORWARD)
def tunnel_forward(r, n):
def tunnel_unit():
force_move(r, Dir.UP)
force_move(r, Dir.FORWARD)
force_move(r, Dir.DOWN)
force_move(r, Dir.FORWARD)
# if n is odd
if n % 2 != 0:
for _ in range(math.floor(n/2)):
tunnel_unit()
force_move(r, Dir.UP)
force_move(r, Dir.DOWN)
# else n is even
else:
for _ in range(math.floor(n/2) - 1):
tunnel_unit()
force_move(r, Dir.UP)
force_move(r, Dir.FORWARD)
force_move(r, Dir.DOWN)
def fill_to_loc(r, loc, bt):
r_loc = r.get_location()
print("Filling from ", r_loc, " to ", loc)
locs = get_loc_path(r_loc, loc)
prev_loc = locs[0]
for i in range(1, len(locs)):
new_loc = locs[i]
force_move(r, new_loc)
d = new_loc.direction(prev_loc)
if r.place(d, bt) == False:
print("ERROR fill_to_loc: block placement unsuccessful")
return
prev_loc = new_loc
def hilbert_fractal_locs(start_loc, num_dims, size):
hil = Hilbert(num_dims, size)
locs = []
for i in range(0, size**num_dims-1):
p = hil.point(i)
print("p: ", p)
x = p[0] * 2 + start_loc.x_coord
y = p[1] * 2 + start_loc.y_coord
z = p[2] * 2 + start_loc.z_coord
locs.append( Location(x,y,z) )
return locs
def make_3d_hilbert_fractal(r, start_loc, size):
print("Starting hilbert fractal at:", start_loc)
force_goto_loc(r, start_loc)
locs = hilbert_fractal_locs(start_loc, 3, size)
for i in range(0, len(locs) - 2):
print(locs[i])
fill_to_loc(r, locs[i+1], BlockType.COBBLESTONE)
print("Finished hilbert fractal")
def clear_area(r, loc_a, loc_b):
ax = loc_a.x_coord
ay = loc_a.y_coord
az = loc_a.z_coord
bx = loc_b.x_coord
by = loc_b.y_coord
bz = loc_b.z_coord
xs = range(ax, bx) if ax < bx else range(bx, ax)
ys = range(ay, by) if ay < by else range(by, ay)
zs = range(az, bz) if az < bz else range(bz, az)
locs = [Location(x,y,z) for x in xs for y in ys for z in zs]
for loc in locs:
force_goto_loc(r, loc)
def count_inventory_item(r, bid):
inv = r.get_inventory()
maybe_items = [item for item in inv if item[0] == bid]
if len(maybe_items) == 0:
return 0
else:
return maybe_items[0][1]
def adjacent_blocks(r):
dirs = [
Dir.UP,
Dir.DOWN,
Dir.NORTH,
Dir.EAST,
Dir.SOUTH,
Dir.WEST
]
blocks = []
for d in dirs:
blocks.append( r.get_block_type(d) )
return blocks
def loc_plus_dir(loc, d):
x = loc.x_coord
y = loc.y_coord
z = loc.z_coord
if d == Dir.UP:
return Location(x,y+1,z)
elif d == Dir.DOWN:
return Location(x,y-1,z)
elif d == Dir.EAST:
return Location(x+1,y,z)
elif d == Dir.WEST:
return Location(x-1,y,z)
elif d == Dir.NORTH:
return Location(x,y,z-1)
elif d == Dir.SOUTH:
return Location(x,y,z+1)
def hunt(r, bid):
# Mine all adjacent occurences of bid
# Won't get any that are diagonal to the other blocks
# robot.find_type_nearby(..) puts far too much load on the server to be
# useful.
print("Hunting for: ", bid)
dirs = [
Dir.UP,
Dir.DOWN,
Dir.NORTH,
Dir.EAST,
Dir.SOUTH,
Dir.WEST
]
locs = []
def check_adjacents():
for d in dirs:
if r.get_block_type(d) == bid:
locs.append( loc_plus_dir(r.get_location(), d) )
check_adjacents()
while len(locs) > 0:
force_goto_loc(r, locs.pop())
check_adjacents()
def mine_ores(r, diamond_goal):
# First mine down to level 10
start_loc = r.get_location()
start_loc.y_coord = 10
safe_goto_loc(r, start_loc)
# Side length for spiral which will be dug: this is incremented at every
# iteration.
s = 1
r.turn(Dir.NORTH)
rare_blocks = [
BlockType.DIAMOND_ORE,
BlockType.GOLD_ORE,
BlockType.IRON_ORE,
BlockType.OBSIDIAN,
BlockType.REDSTONE_ORE,
BlockType.LAPIS_ORE,
BlockType.COAL_ORE
]
while True:
for bid in rare_blocks:
if bid in adjacent_blocks(r):
# Allows pockets of rare blocks to be mined:
# Save the current location and return to it after mining
# a pocket.
start_loc = r.get_location()
hunt(r, bid)
force_goto_loc(r, start_loc)
diamond_count = count_inventory_item(r, BlockType.DIAMOND)
if diamond_count >= diamond_goal:
print("Diamond goal reached... returning to owner.")
goto_owner(r)
return
# Mine in an ever-increasing spiral
forward(r, s)
r.turn(Dir.RIGHT)
s += 1
print("Robot turned right again, spiral side length: ", s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment