VirtualQueryEx returning impossible mbi.RegionSize value in ctypes - ctypes

I'm building a Memory Scanner and in the middle of it I use VirtualQueryEx to get the size in bytes of the process.
This is my VirtualQueryEx and MEMORY_BASIC_INFORMATION structure setups:
VirtualQueryEx = windll.kernel32.VirtualQueryEx
VirtualQueryEx.restype = c_size_t
class MEMORY_BASIC_INFORMATION(Structure):
_fields_ = [
("BaseAddress", c_ulonglong),
("AllocationBase", c_ulonglong),
("AllocationProtect", c_ulong),
("__alignment1", c_ulong),
("RegionSize", c_ulonglong),
("State", c_ulong),
("Protect", c_ulong),
("Type", c_ulong),
("__alignment2", c_ulong),
]
VirtualQueryEx.argtypes = [
wintypes.HANDLE, # [in] HANDLE hProcess
wintypes.LPCVOID, # [in] LPCVOID lpAdress
POINTER(MEMORY_BASIC_INFORMATION), # [out] PMEMORY_BASIC_INFORMATION lpBuffer
c_size_t, # [in] SIZE_T lpBuffer
]
and before I call the function I also define some variables
mbi = MEMORY_BASIC_INFORMATION()
lpAdress = wintypes.LPVOID(None)
hProcess which is a OpenProcess() Handle
then I call it
VirtualQueryEx( hProcess, lpAdress, byref(mbi), sizeof(mbi))
and after I check the output of RegionSide field of MEMORY_BASIC_INFORMATION
mbi.RegionSize
the result is a crazy number of bytes like 135762539134976 which is so big that is probably a wrong value or at least something I dont understand, any ideas ?

Here's a verified working version. The numbers printed for my Python process agree with the SysInternals vmmap utility:
import ctypes as ct
from ctypes import wintypes as w
SIZE_T = ct.c_size_t
# https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
class MEMORY_BASIC_INFORMATION(ct.Structure):
_fields_ = [("BaseAddress", w.LPVOID),
("AllocationBase", w.LPVOID),
("AllocationProtect", w.DWORD),
("PartitionId", w.WORD),
("RegionSize", SIZE_T),
("State", w.DWORD),
("Protect", w.DWORD),
("Type", w.DWORD)]
# Allow this structure to print itself
def __repr__(self):
return f'MEMORY_BASIC_INFORMATION(BaseAddress={self.BaseAddress if self.BaseAddress is not None else 0:#x}, ' \
f'AllocationBase={self.AllocationBase if self.AllocationBase is not None else 0:#x}, ' \
f'AllocationProtect={self.AllocationProtect:#x}, ' \
f'PartitionId={self.PartitionId:#x}, ' \
f'RegionSize={self.RegionSize:#x}, ' \
f'State={self.State:#x}, ' \
f'Protect={self.Protect:#x}, ' \
f'Type={self.Type:#x})'
PMEMORY_BASIC_INFORMATION = ct.POINTER(MEMORY_BASIC_INFORMATION)
dll = ct.WinDLL('kernel32', use_last_error=True)
# https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualqueryex
VirtualQueryEx = dll.VirtualQueryEx
VirtualQueryEx.argtypes = w.HANDLE, w.LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T
VirtualQueryEx.restype = SIZE_T
# https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess
GetCurrentProcess = dll.GetCurrentProcess
GetCurrentProcess.argtypes = ()
GetCurrentProcess.restype = w.HANDLE
h = GetCurrentProcess()
mbi = MEMORY_BASIC_INFORMATION()
# Starting at the beginning of the process' virtual memory,
# query the region and its size, then advance by the region size
# and continue to query until failure.
address = 0
while True:
result = VirtualQueryEx(h, address, ct.byref(mbi), ct.sizeof(mbi))
if result:
print(mbi)
address += mbi.RegionSize
else:
print(f'err={ct.get_last_error()}')
break
Output:
MEMORY_BASIC_INFORMATION(BaseAddress=0x0, AllocationBase=0x0, AllocationProtect=0x0, PartitionId=0x0, RegionSize=0x7ffe0000, State=0x10000, Protect=0x1, Type=0x0)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffe0000, AllocationBase=0x7ffe0000, AllocationProtect=0x2, PartitionId=0x0, RegionSize=0x1000, State=0x1000, Protect=0x2, Type=0x20000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffe1000, AllocationBase=0x0, AllocationProtect=0x0, PartitionId=0x0, RegionSize=0x5000, State=0x10000, Protect=0x1, Type=0x0)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffe6000, AllocationBase=0x7ffe6000, AllocationProtect=0x2, PartitionId=0x0, RegionSize=0x1000, State=0x1000, Protect=0x2, Type=0x20000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffe7000, AllocationBase=0x0, AllocationProtect=0x0, PartitionId=0x0, RegionSize=0x16bce19000, State=0x10000, Protect=0x1, Type=0x0)
...
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffaca6f6000, AllocationBase=0x7ffaca590000, AllocationProtect=0x80, PartitionId=0x0, RegionSize=0x1000, State=0x1000, Protect=0x4, Type=0x1000000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffaca6f7000, AllocationBase=0x7ffaca590000, AllocationProtect=0x80, PartitionId=0x0, RegionSize=0x2000, State=0x1000, Protect=0x8, Type=0x1000000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffaca6f9000, AllocationBase=0x7ffaca590000, AllocationProtect=0x80, PartitionId=0x0, RegionSize=0x9000, State=0x1000, Protect=0x4, Type=0x1000000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffaca702000, AllocationBase=0x7ffaca590000, AllocationProtect=0x80, PartitionId=0x0, RegionSize=0x86000, State=0x1000, Protect=0x2, Type=0x1000000)
MEMORY_BASIC_INFORMATION(BaseAddress=0x7ffaca788000, AllocationBase=0x0, AllocationProtect=0x0, PartitionId=0x0, RegionSize=0x535868000, State=0x10000, Protect=0x1, Type=0x0)
err=87

Related

Is there a way to take a list of strings and create a JSON file, where both the key and value are list items?

I am creating a python script that can read scanned, and tabular .pdfs and extract some important data and insert it into a JSON to later be implemented into a SQL database (I will also be developing the DB as a project for learning MongoDB).
Basically, my issue is I have never worked with any JSON files before but that was the format I was recommended to output to. The scraping script works, the pre-processing could be a lot cleaner, but for now it works. The issue I run into is the keys, and values are in the same list, and some of the values because they had a decimal point are two different list items. Not really sure where to even start.
I don't really know where to start, I suppose since I know what the indexes of the list are I can easily assign keys and values, but then it may not be applicable to any .pdf, that is the script cannot be coded explicitly.
import PyPDF2 as pdf2
import textract
with "TestSpec.pdf" as filename:
pdfFileObj = open(filename, 'rb')
pdfReader = pdf2.pdfFileReader(pdfFileObj)
num_pages = pdfReader.numpages
count = 0
text = ""
while count < num_pages:
pageObj = pdfReader.getPage(0)
count += 1
text += pageObj.extractText()
if text != "":
text = text
else:
text = textract.process(filename, method="tesseract", language="eng")
def cleanText(x):
'''
This function takes the byte data extracted from scanned PDFs, and cleans it of all
unnessary data.
Requires re
'''
stringedText = str(x)
cleanText = stringedText.replace('\n','')
splitText = re.split(r'\W+', cleanText)
caseingText = [word.lower() for word in splitText]
cleanOne = [word for word in caseingText if word != 'n']
dexStop = cleanOne.index("od260")
dexStart = cleanOne.index("sheet")
clean = cleanOne[dexStart + 1:dexStop]
return clean
cleanText = cleanText(text)
This is the current output
['n21', 'feb', '2019', 'nsequence', 'lacz', 'rp', 'n5', 'gat', 'ctc', 'tac', 'cat', 'ggc', 'gca', 'cat', 'ttc', 'ccc', 'gaa', 'aag', 'tgc', '3', 'norder', 'no', '15775199', 'nref', 'no', '207335463', 'n25', 'nmole', 'dna', 'oligo', '36', 'bases', 'nproperties', 'amount', 'of', 'oligo', 'shipped', 'to', 'ntm', '50mm', 'nacl', '66', '8', 'xc2', 'xb0c', '11', '0', '32', '6', 'david', 'cook', 'ngc', 'content', '52', '8', 'd260', 'mmoles', 'kansas', 'state', 'university', 'biotechno', 'nmolecular', 'weight', '10', '965', '1', 'nnmoles']
and we want the output as a JSON setup like
{"Date | 21feb2019", "Sequence ID: | lacz-rp", "Sequence 5'-3' | gat..."}
and so on. Just not sure how to do that.
here is a screenshot of the data from my sample pdf
So, i have figured out some of this. I am still having issues with grabbing the last 3rd of the data i need without explicitly programming it in. but here is what i have so far. Once i have everything working then i will worry about optimizing it and condensing.
# for PDF reading
import PyPDF2 as pdf2
import textract
# for data preprocessing
import re
from dateutil.parser import parse
# For generating the JSON file array
import json
# This finds and opens the pdf file, reads the data, and extracts the data.
filename = "*.pdf"
pdfFileObj = open(filename, 'rb')
pdfReader = pdf2.PdfFileReader(pdfFileObj)
text = ""
pageObj = pdfReader.getPage(0)
text += pageObj.extractText()
# checks if extracted data is in string form or picture, if picture textract reads data.
# it then closes the pdf file
if text != "":
text = text
else:
text = textract.process(filename, method="tesseract", language="eng")
pdfFileObj.close()
# Converts text to string from byte data for preprocessing
stringedText = str(text)
# Removed escaped lines and replaced them with actual new lines.
formattedText = stringedText.replace('\\n', '\n').lower()
# Slices the long string into a workable piece (only contains useful data)
slice1 = formattedText[(formattedText.index("sheet") + 10): (formattedText.index("secondary") - 2)]
clean = re.sub('\n', " ", slice1)
clean2 = re.sub(' +', ' ', clean)
# Creating the PrimerData dictionary
with open("PrimerData.json",'w') as file:
primerDataSlice = clean[clean.index("molecular"): -1]
primerData = re.split(": |\n", primerDataSlice)
primerKeys = primerData[0::2]
primerValues = primerData[1::2]
primerDict = {"Primer Data": dict(zip(primerKeys,primerValues))}
# Generatring the JSON array "Primer Data"
primerJSON = json.dumps(primerDict, ensure_ascii=False)
file.write(primerJSON)
# Grabbing the date (this has just the date, so json will have to add date.)
date = re.findall('(\d{2}[\/\- ](\d{2}|january|jan|february|feb|march|mar|april|apr|may|may|june|jun|july|jul|august|aug|september|sep|october|oct|november|nov|december|dec)[\/\- ]\d{2,4})', clean2)
Without input data it is difficult to give you working code. A minimal working example with input would help. As for JSON handling, python dictionaries can dump to json easily. See examples here.
https://docs.python-guide.org/scenarios/json/
Get a json string from a dictionary and write to a file. Figure out how to parse the text into a dictionary.
import json
d = {"Date" : "21feb2019", "Sequence ID" : "lacz-rp", "Sequence 5'-3'" : "gat"}
json_data = json.dumps(d)
print(json_data)
# Write that data to a file
So, I did figure this out, the problem was really just that because of the way my pre-processing was pulling all the data into a single list wasn't really that great of an idea considering that the keys for the dictionary never changed.
Here is the semi-finished result for making the Dictionary and JSON file.
# Collect the sequence name
name = clean2[clean2.index("Sequence") + 11: clean2.index("Sequence") + 19]
# Collecting Shipment info
ordered = input("Who placed this order? ")
received = input("Who is receiving this order? ")
dateOrder = re.findall(
r"(\d{2}[/\- ](\d{2}|January|Jan|February|Feb|March|Mar|April|Apr|May|June|Jun|July|Jul|August|Aug|September|Sep|October|Oct|November|Nov|December|Dec)[/\- ]\d{2,4})",
clean2)
dateReceived = date.today()
refNo = clean2[clean2.index("ref.No. ") + 8: clean2.index("ref.No.") + 17]
orderNo = clean2[clean2.index("Order No.") +
10: clean2.index("Order No.") + 18]
# Finding and grabbing the sequence data. Storing it and then finding the
# GC content and melting temp or TM
bases = int(clean2[clean2.index("bases") - 3:clean2.index("bases") - 1])
seqList = [line for line in clean2 if re.match(r'^[AGCT]+$', line)]
sequence = "".join(i for i in seqList[:bases])
def gc_content(x):
count = 0
for i in x:
if i == 'G' or i == 'C':
count += 1
else:
count = count
return round((count / bases) * 100, 1)
gc = gc_content(sequence)
tm = mt.Tm_GC(sequence, Na=50)
moleWeight = round(mw(Seq(sequence, generic_dna)), 2)
dilWeight = float(clean2[clean2.index("ug/OD260:") +
10: clean2.index("ug/OD260:") + 14])
dilution = dilWeight * 10
primerDict = {"Primer Data": {
"Sequence": sequence,
"Bases": bases,
"TM (50mM NaCl)": tm,
"% GC content": gc,
"Molecular weight": moleWeight,
"ug/0D260": dilWeight,
"Dilution volume (uL)": dilution
},
"Shipment Info": {
"Ref. No.": refNo,
"Order No.": orderNo,
"Ordered by": ordered,
"Date of Order": dateOrder,
"Received By": received,
"Date Received": str(dateReceived.strftime("%d-%b-%Y"))
}}
# Generating the JSON array "Primer Data"
with open("".join(name) + ".json", 'w') as file:
primerJSON = json.dumps(primerDict, ensure_ascii=False)
file.write(primerJSON)

Object of type 'closure' is not subsettable - R

I am using R to extract tweets and analyse their sentiment, however when I get to the lines below I get an error saying "Object of type 'closure' is not subsettable"
scores$drink = factor(rep(c("east"), nd))
scores$very.pos = as.numeric(scores$score >= 2)
scores$very.neg = as.numeric(scores$score <= -2)
Full code pasted below
load("twitCred.Rdata")
east_tweets <- filterStream("tweetselnd.json", locations = c(-0.10444, 51.408699, 0.33403, 51.64661),timeout = 120, oauth = twitCred)
tweets.df <- parseTweets("tweetselnd.json", verbose = FALSE)
##function score.sentiment
score.sentiment = function(sentences, pos.words, neg.words, .progress='none')
{
# Parameters
# sentences: vector of text to score
# pos.words: vector of words of postive sentiment
# neg.words: vector of words of negative sentiment
# .progress: passed to laply() to control of progress bar
scores = laply(sentences,
function(sentence, pos.words, neg.words)
{
# remove punctuation
sentence = gsub("[[:punct:]]", "", sentence)
# remove control characters
sentence = gsub("[[:cntrl:]]", "", sentence)
# remove digits?
sentence = gsub('\\d+', '', sentence)
# define error handling function when trying tolower
tryTolower = function(x)
{
# create missing value
y = NA
# tryCatch error
try_error = tryCatch(tolower(x), error=function(e) e)
# if not an error
if (!inherits(try_error, "error"))
y = tolower(x)
# result
return(y)
}
# use tryTolower with sapply
sentence = sapply(sentence, tryTolower)
# split sentence into words with str_split (stringr package)
word.list = str_split(sentence, "\\s+")
words = unlist(word.list)
# compare words to the dictionaries of positive & negative terms
pos.matches = match(words, pos.words)
neg.matches = match(words, neg.words)
# get the position of the matched term or NA
# we just want a TRUE/FALSE
pos.matches = !is.na(pos.matches)
neg.matches = !is.na(neg.matches)
# final score
score = sum(pos.matches) - sum(neg.matches)
return(score)
}, pos.words, neg.words, .progress=.progress )
# data frame with scores for each sentence
scores.df = data.frame(text=sentences, score=scores)
return(scores.df)
}
pos = readLines(file.choose())
neg = readLines(file.choose())
east_text = sapply(east_tweets, function(x) x$getText())
scores = score.sentiment(tweetseldn.json, pos, neg, .progress='text')
scores()$drink = factor(rep(c("east"), nd))
scores()$very.pos = as.numeric(scores()$score >= 2)
scores$very.neg = as.numeric(scores$score <= -2)
# how many very positives and very negatives
numpos = sum(scores$very.pos)
numneg = sum(scores$very.neg)
# global score
global_score = round( 100 * numpos / (numpos + numneg) )
If anyone could help with as to why I'm getting this error it will be much appreciated. Also I've seen other answeres about adding '()' when referring to the variable 'scores' such as scores()$.... but it hasn't worked for me. Thank you.
The changes below got rid of the error:
x <- scores
x$drink = factor(rep(c("east"), nd))
x$very.pos = as.numeric(x$score >= 2)
x$very.neg = as.numeric(x$score <= -2)

Mkfifo in GNU Octave

I have yet to find a complete example for using the mkfifo() function online. I am able to make the fifo like this:
mkfifo("file",777)
But when I fopen() this file, Octave just hangs. What is the proper way to create, queue, and dequeue bytes from a mkfifo object?
I would like to create an in-memory fifo in Octave (on-disk is fine too) and read and write it from the same Octave script. My project is running in real time, and so I need a buffer so that I can fill and drain from the same Octave script. I've searched for a fifo library with zero results. Even just creating a vector and pushing and popping will suit my needs. I tried this myself, but I'm running into object oriented programming design problems because Octave does not allow pass by reference or pointers.
There are two issues. First: mkfifo expects mode as integer with base 10, if you write "777" you think in octal, base 8. Second: mkfifo uses umask to modify the permissions to (mode & ~umask) (See man 3)
As example:
fn=tempname
[ERR, MSG] = mkfifo (fn, base2dec("744", 8))
stat(fn)
fn = /tmp/oct-83UCBR
ERR = 0
MSG =
ans =
scalar structure containing the fields:
dev = 2053
ino = 3408172
mode = 4580
modestr = prwxr--r--
nlink = 1
uid = 1000
gid = 1000
rdev = 0
size = 0
atime = 1.4311e+09
mtime = 1.4311e+09
ctime = 1.4311e+09
blksize = 4096
blocks = 0
As you can see the modestr is now prwxr--r-- as you would expect from octal 744
Now you can open one end of the FIFO:
fid = fopen (fn, "r")
Of course this blocks until the other end of the fifo gets connected.
The fifo class works, but only up to a certain size. The max size in bytes of a fifo can be found by running:
cat /proc/sys/fs/pipe-max-size
1048576
Below is the code that I wrote for an in-memory fifo. It's fairly crude but it works well:
1; % Prevent Octave from thinking that this is a function file
global fifoCount fifoSamples fifoFiles fifoFids fifoDataType
fifoSamples = zeros(0);
fifoCount = 0;
fifoFiles = cell(1);
fifoFids = zeros(0);
fifoDataType = 'single';
fifoDataTypeSize = 4;
fifoMaxBytes = 1048576; % this is operating system enforced, changing here will not help
function [] = o_fifo_write(index, data)
global fifoCount fifoSamples fifoFiles fifoFids fifoDataType
wrcount = fwrite(fifoFids(index), data, fifoDataType);
[sz,~] = size(data);
fifoSamples(index) = fifoSamples(index) + sz;
if( sz ~= wrcount )
disp(sprintf('o_fifo_write was given %d samples but wrote %d', sz, wrcount));
end
if( ~iscolumn(data) )
disp('data must be columnar in o_fifo_write');
end
end
function [data] = o_fifo_read(index, count)
global fifoCount fifoSamples fifoFiles fifoFids fifoDataType
[data, rdcount] = fread(fifoFids(index), count, fifoDataType);
[sz,~] = size(data);
fifoSamples(index) = fifoSamples(index) - sz;
if( sz ~= rdcount || sz ~= count )
disp(sprintf('in o_fifo_read %d %d %d should all be the same', sz, rdcount, count));
end
end
function [avail] = o_fifo_avail(index)
global fifoCount fifoSamples fifoFiles fifoFids fifoDataType
avail = fifoSamples(index);
end
function index = o_fifo_new()
global fifoCount fifoSamples fifoFiles fifoFids fifoDataType
fifoCount = fifoCount + 1;
index = fifoCount;
fifoSamples(index) = 0;
fifoFiles{index} = tempname;
[ERR, MSG] = mkfifo(fifoFiles{index}, base2dec('744',8));
fifoFids(index) = fopen(fifoFiles{index}, 'a+');
% fcntl(fifoFids(index), F_SETFL, O_NONBLOCK); % uncomment to avoid hangs when trying to overfill fifo
end
% ---- usage -----
txfifo = o_fifo_new();
disp(o_fifo_avail(txfifo));
o_fifo_write(txfifo, [1.243 pi 2*pi 4/3*pi]');
disp(o_fifo_avail(txfifo));
disp(o_fifo_read(txfifo, 4));
disp(o_fifo_avail(txfifo));

HBase shell scan bytes to string conversion

I would like to scan hbase table and see integers as strings (not their binary representation). I can do the conversion but have no idea how to write scan statement by using Java API from hbase shell:
org.apache.hadoop.hbase.util.Bytes.toString(
"\x48\x65\x6c\x6c\x6f\x20\x48\x42\x61\x73\x65".to_java_bytes)
org.apache.hadoop.hbase.util.Bytes.toString("Hello HBase".to_java_bytes)
I will be very happy to have examples of scan, get that searching binary data (long's) and output normal strings. I am using hbase shell, not JAVA.
HBase stores data as byte arrays (untyped). Therefore if you perform a table scan data will be displayed in a common format (escaped hexadecimal string), e.g: "\x48\x65\x6c\x6c\x6f\x20\x48\x42\x61\x73\x65" -> Hello HBase
If you want to get back the typed value from the serialized byte array you have to do this manually.
You have the following options:
Java code (Bytes.toString(...))
hack the to_string function in $HBASE/HOME/lib/ruby/hbase/table.rb :
replace toStringBinary with toInt for non-meta tables
write a get/scan JRuby function which converts the byte array to the appropriate type
Since you want it HBase shell, then consider the last option:
Create a file get_result.rb :
import org.apache.hadoop.hbase.HBaseConfiguration
import org.apache.hadoop.hbase.client.HTable
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Result;
import java.util.ArrayList;
# Simple function equivalent to scan 'test', {COLUMNS => 'c:c2'}
def get_result()
htable = HTable.new(HBaseConfiguration.new, "test")
rs = htable.getScanner(Bytes.toBytes("c"), Bytes.toBytes("c2"))
output = ArrayList.new
output.add "ROW\t\t\t\t\t\tCOLUMN\+CELL"
rs.each { |r|
r.raw.each { |kv|
row = Bytes.toString(kv.getRow)
fam = Bytes.toString(kv.getFamily)
ql = Bytes.toString(kv.getQualifier)
ts = kv.getTimestamp
val = Bytes.toInt(kv.getValue)
output.add " #{row} \t\t\t\t\t\t column=#{fam}:#{ql}, timestamp=#{ts}, value=#{val}"
}
}
output.each {|line| puts "#{line}\n"}
end
load it in the HBase shell and use it:
require '/path/to/get_result'
get_result
Note: modify/enhance/fix the code according to your needs
Just for completeness' sake, it turns out that the call Bytes::toStringBinary gives the hex-escaped sequence you get in HBase shell:
\x0B\x2_SOME_ASCII_TEXT_\x10\x00...
Whereas, Bytes::toString will try to deserialize to a string assuming UTF8, which will look more like:
\u8900\u0710\u0115\u0320\u0000_SOME_UTF8_TEXT_\u4009...
you can add a scan_counter command to the hbase shell.
first:
add to /usr/lib/hbase/lib/ruby/hbase/table.rb (after the scan function):
#----------------------------------------------------------------------------------------------
# Scans whole table or a range of keys and returns rows matching specific criterias with values as number
def scan_counter(args = {})
unless args.kind_of?(Hash)
raise ArgumentError, "Arguments should be a hash. Failed to parse #{args.inspect}, #{args.class}"
end
limit = args.delete("LIMIT") || -1
maxlength = args.delete("MAXLENGTH") || -1
if args.any?
filter = args["FILTER"]
startrow = args["STARTROW"] || ''
stoprow = args["STOPROW"]
timestamp = args["TIMESTAMP"]
columns = args["COLUMNS"] || args["COLUMN"] || get_all_columns
cache = args["CACHE_BLOCKS"] || true
versions = args["VERSIONS"] || 1
timerange = args[TIMERANGE]
# Normalize column names
columns = [columns] if columns.class == String
unless columns.kind_of?(Array)
raise ArgumentError.new("COLUMNS must be specified as a String or an Array")
end
scan = if stoprow
org.apache.hadoop.hbase.client.Scan.new(startrow.to_java_bytes, stoprow.to_java_bytes)
else
org.apache.hadoop.hbase.client.Scan.new(startrow.to_java_bytes)
end
columns.each { |c| scan.addColumns(c) }
scan.setFilter(filter) if filter
scan.setTimeStamp(timestamp) if timestamp
scan.setCacheBlocks(cache)
scan.setMaxVersions(versions) if versions > 1
scan.setTimeRange(timerange[0], timerange[1]) if timerange
else
scan = org.apache.hadoop.hbase.client.Scan.new
end
# Start the scanner
scanner = #table.getScanner(scan)
count = 0
res = {}
iter = scanner.iterator
# Iterate results
while iter.hasNext
if limit > 0 && count >= limit
break
end
row = iter.next
key = org.apache.hadoop.hbase.util.Bytes::toStringBinary(row.getRow)
row.list.each do |kv|
family = String.from_java_bytes(kv.getFamily)
qualifier = org.apache.hadoop.hbase.util.Bytes::toStringBinary(kv.getQualifier)
column = "#{family}:#{qualifier}"
cell = to_string_scan_counter(column, kv, maxlength)
if block_given?
yield(key, "column=#{column}, #{cell}")
else
res[key] ||= {}
res[key][column] = cell
end
end
# One more row processed
count += 1
end
return ((block_given?) ? count : res)
end
#----------------------------------------------------------------------------------------
# Helper methods
# Returns a list of column names in the table
def get_all_columns
#table.table_descriptor.getFamilies.map do |family|
"#{family.getNameAsString}:"
end
end
# Checks if current table is one of the 'meta' tables
def is_meta_table?
tn = #table.table_name
org.apache.hadoop.hbase.util.Bytes.equals(tn, org.apache.hadoop.hbase.HConstants::META_TABLE_NAME) || org.apache.hadoop.hbase.util.Bytes.equals(tn, org.apache.hadoop.hbase.HConstants::ROOT_TABLE_NAME)
end
# Returns family and (when has it) qualifier for a column name
def parse_column_name(column)
split = org.apache.hadoop.hbase.KeyValue.parseColumn(column.to_java_bytes)
return split[0], (split.length > 1) ? split[1] : nil
end
# Make a String of the passed kv
# Intercept cells whose format we know such as the info:regioninfo in .META.
def to_string(column, kv, maxlength = -1)
if is_meta_table?
if column == 'info:regioninfo' or column == 'info:splitA' or column == 'info:splitB'
hri = org.apache.hadoop.hbase.util.Writables.getHRegionInfoOrNull(kv.getValue)
return "timestamp=%d, value=%s" % [kv.getTimestamp, hri.toString]
end
if column == 'info:serverstartcode'
if kv.getValue.length > 0
str_val = org.apache.hadoop.hbase.util.Bytes.toLong(kv.getValue)
else
str_val = org.apache.hadoop.hbase.util.Bytes.toStringBinary(kv.getValue)
end
return "timestamp=%d, value=%s" % [kv.getTimestamp, str_val]
end
end
val = "timestamp=#{kv.getTimestamp}, value=#{org.apache.hadoop.hbase.util.Bytes::toStringBinary(kv.getValue)}"
(maxlength != -1) ? val[0, maxlength] : val
end
def to_string_scan_counter(column, kv, maxlength = -1)
if is_meta_table?
if column == 'info:regioninfo' or column == 'info:splitA' or column == 'info:splitB'
hri = org.apache.hadoop.hbase.util.Writables.getHRegionInfoOrNull(kv.getValue)
return "timestamp=%d, value=%s" % [kv.getTimestamp, hri.toString]
end
if column == 'info:serverstartcode'
if kv.getValue.length > 0
str_val = org.apache.hadoop.hbase.util.Bytes.toLong(kv.getValue)
else
str_val = org.apache.hadoop.hbase.util.Bytes.toStringBinary(kv.getValue)
end
return "timestamp=%d, value=%s" % [kv.getTimestamp, str_val]
end
end
val = "timestamp=#{kv.getTimestamp}, value=#{org.apache.hadoop.hbase.util.Bytes::toLong(kv.getValue)}"
(maxlength != -1) ? val[0, maxlength] : val
end
second:
add to /usr/lib/hbase/lib/ruby/shell/commands/
the following file called: scan_counter.rb
#
# Copyright 2010 The Apache Software Foundation
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module Shell
module Commands
class ScanCounter < Command
def help
return <<-EOF
Scan a table with cell value that is long; pass table name and optionally a dictionary of scanner
specifications. Scanner specifications may include one or more of:
TIMERANGE, FILTER, LIMIT, STARTROW, STOPROW, TIMESTAMP, MAXLENGTH,
or COLUMNS. If no columns are specified, all columns will be scanned.
To scan all members of a column family, leave the qualifier empty as in
'col_family:'.
Some examples:
hbase> scan_counter '.META.'
hbase> scan_counter '.META.', {COLUMNS => 'info:regioninfo'}
hbase> scan_counter 't1', {COLUMNS => ['c1', 'c2'], LIMIT => 10, STARTROW => 'xyz'}
hbase> scan_counter 't1', {FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)}
hbase> scan_counter 't1', {COLUMNS => 'c1', TIMERANGE => [1303668804, 1303668904]}
For experts, there is an additional option -- CACHE_BLOCKS -- which
switches block caching for the scanner on (true) or off (false). By
default it is enabled. Examples:
hbase> scan_counter 't1', {COLUMNS => ['c1', 'c2'], CACHE_BLOCKS => false}
EOF
end
def command(table, args = {})
now = Time.now
formatter.header(["ROW", "COLUMN+CELL"])
count = table(table).scan_counter(args) do |row, cells|
formatter.row([ row, cells ])
end
formatter.footer(now, count)
end
end
end
end
finally
add to /usr/lib/hbase/lib/ruby/shell.rb the function scan_counter.
replace the current function with this: (you can identify it by: 'DATA MANIPULATION COMMANDS',)
Shell.load_command_group(
'dml',
:full_name => 'DATA MANIPULATION COMMANDS',
:commands => %w[
count
delete
deleteall
get
get_counter
incr
put
scan
scan_counter
truncate
]
)

Code Golf: Lasers

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
The challenge
The shortest code by character count to input a 2D representation of a board, and output 'true' or 'false' according to the input.
The board is made out of 4 types of tiles:
# - A solid wall
x - The target the laser has to hit
/ or \ - Mirrors pointing to a direction (depends on laser direction)
v, ^, > or < - The laser pointing to a direction (down, up, right and left respectively)
There is only one laser and only one target. Walls must form a solid rectangle of any size, where the laser and target are placed inside. Walls inside the 'room' are possible.
Laser ray shots and travels from its origin to the direction it's pointing. If a laser ray hits the wall, it stops. If a laser ray hits a mirror, it bounces 90 degrees to the direction the mirror points to. Mirrors are two sided, meaning both sides are 'reflective' and may bounce a ray in two ways. If a laser ray hits the laser (^v><) itself, it is treated as a wall (laser beam destroys the beamer and so it'll never hit the target).
Test cases
Input:
##########
# / \ #
# #
# \ x#
# > / #
##########
Output:
true
Input:
##########
# v x #
# / #
# /#
# \ #
##########
Output:
false
Input:
#############
# # #
# > # #
# # #
# # x #
# # #
#############
Output:
false
Input:
##########
#/\/\/\ #
#\\//\\\ #
#//\/\/\\#
#\/\/\/x^#
##########
Output:
true
Code count includes input/output (i.e full program).
Perl, 166 160 characters
Perl, 251 248 246 222 214 208 203 201 193 190 180 176 173 170 166 --> 160 chars.
Solution had 166 strokes when this contest ended, but A. Rex has found a couple ways to shave off 6 more characters:
s!.!$t{$s++}=$&!ge,$s=$r+=99for<>;%d='>.^1<2v3'=~/./g;($r)=grep$d|=$d{$t{$_}},%t;
{$_=$t{$r+=(1,-99,-1,99)[$d^=3*/\\/+m</>]};/[\/\\ ]/&&redo}die/x/?true:false,$/
The first line loads the input into %t, a table of the board where $t{99*i+j} holds the character at row i,column j. Then,
%d=split//,'>.^1<2v3' ; ($r)=grep{$d|=$d{$t{$_}}}%t
it searches the elements of %t for a character that matches > ^ < or v, and simultaneously sets $d to a value between 0 and 3 that indicates the initial direction of the laser beam.
At the beginning of each iteration in the main loop, we update $d if the beam is currently on a mirror. XOR'ing by 3 gives the correct behavior for a \ mirror and XOR'ing by 1 gives the correct behavior for a / mirror.
$d^=3*/\\/+m</>
Next, the current position $r is updated accoring to the current direction.
$r+=(1,-99,-1,99)[$d] ; $_ = $t{$r}
We assign the character at the current position to $_ to make convenient use of the match operators.
/[\/\\ ]/ && redo
Continue if we are on a blank space or a mirror character. Otherwise we terminate true if we are on the target ($_ =~ /x/) and false otherwise.
Limitation: may not work on problems with more than 99 columns. This limitation could be removed at the expense of 3 more characters,
Perl, 177 Characters
The first linebreak can be removed; the other two are mandatory.
$/=%d=split//,' >/^\v';$_=<>;$s='#';{
y/v<^/>v</?do{my$o;$o.="
"while s/.$/$o.=$&,""/meg;y'/\\'\/'for$o,$s;$_=$o}:/>x/?die"true
":/>#/?die"false
":s/>(.)/$s$d{$1}/?$s=$1:1;redo}
Explanation:
$/ = %d = (' ' => '>', '/' => '^', '\\' => 'v');
If a right-moving beam runs into an {empty space, up-angled mirror, down-angled mirror} it becomes a {right-moving beam, up-moving beam, down-moving beam}. Initialize $/ along the way -- fortunately "6" is not a valid input char.
$_ = <>;
Read the board into $_.
$s="#";
$s is the symbol of whatever the beam is sitting on top of now. Since the laser emitter is to be treated like a wall, set this to be a wall to begin with.
if (tr/v<^/>v</) {
my $o;
$o .= "\n" while s/.$/$o .= $&, ""/meg;
tr,/\\,\\/, for $o, $s;
$_ = $o;
}
If the laser beam is pointing any way except right, rotate its symbol, and then rotate the whole board in place (also rotating the symbols for the mirrors). It's a 90 degree left rotation, accomplished effectively by reversing the rows while transposing rows and columns, in a slightly fiendish s///e with side effects. In the golfed code, the tr is written in the form y''' which allows me to skip backslashing one backslash.
die "true\n" if />x/; die "false\n" if />#/;
Terminate with the right message if we hit the target or a wall.
$s = $1 if s/>(.)/$s$d{$1}/;
If there's an empty space in front of the laser, move forward. If there's a mirror in front of the laser, move forward and rotate the beam. In either case, put the "saved symbol" back into the old beam location, and put the thing we just overwrote into the saved symbol.
redo;
Repeat until termination. {...;redo} is two characters less than for(;;){...} and three less than while(1){...}.
C89 (209 characters)
#define M(a,b)*p==*#a?m=b,*p=1,q=p:
*q,G[999],*p=G;w;main(m){for(;(*++p=getchar())>0;)M(<,-1)M
(>,1)M(^,-w)M(v,w)!w&*p<11?w=p-G:0;for(;q+=m,m=*q&4?(*q&1?
-1:1)*(m/w?m/w:m*w):*q&9?!puts(*q&1?"false":"true"):m;);}
Explanation
This monstrosity will probably be difficult to follow if you don't understand C. Just a forewarning.
#define M(a,b)*p==*#a?m=b,*p=1,q=p:
This little macro checks if the current character (*p) is equal to whatever a is in character form (*#a). If they are equal, set the movement vector to b (m=b), mark this character as a wall (*p=1), and set the starting point to the current location (q=p). This macro includes the "else" portion.
*q,G[999],*p=G;
w;
Declare some variables.
* q is the light's current location.
* G is the game board as a 1D array.
* p is the current read location when populating G.
* w is the board's width.
main(m){
Obvious main. m is a variable storing the movement vector. (It's a parameter to main as an optimization.)
for(;(*++p=getchar())>0;)
Loop through all characters, populating G using p. Skip G[0] as an optimization (no need to waste a character writing p again in the third part of the for).
M(<,-1)
M(>,1)
M(^,-w)
M(v,w)
Use the aforementioned macro to define the lazer, if possible. -1 and 1 correspond to left and right, respectively, and -w and w up and down.
!w&*p<11
?w=p-G
:0;
If the current character is an end-of-line marker (ASCII 10), set the width if it hasn't already been set. The skipped G[0] allows us to write w=p-G instead of w=p-G+1. Also, this finishes off the ?: chain from the M's.
for(;
q+=m,
Move the light by the movement vector.
m=
*q&4
?(*q&1?-1:1)*(
m/w?m/w:m*w
)
Reflect the movement vector.
:*q&9
?!puts(*q&1?"false":"true")
:m
;
If this is a wall or x, quit with the appropriate message (m=0 terminates the loop). Otherwise, do nothing (noop; m=m)
);
}
I would bet people have been waiting for this one for a LOOOOONG time. (What do you mean, the challenge is over and nobody cares any more?)
Behold... I here present a solution in
Befunge-93!
It weighs in at a whopping 973 charaters (or 688 if you are charitable enough to ignore whitespace, which is only used for formatting and does nothing in actual code).
Caveat: I wrote my own Befunge-93 interpreter in Perl a short while ago, and unfortunately this is all I've really had time with which to test it. I'm reasonably confident in its correctness in general, but it might have an odd limitation with regard to EOF: Since Perl's <> operator returns undef at the end of file, this is processed as a 0 in the numeric context. For C-based implementations where EOF has a different value (-1 say), this code might not work.
003pv >~v> #v_"a"43g-!#v_23g03p33v>v
>39#<*v :: >:52*-!v >"rorrE",vg2*
######1 >^vp31+1g31$_03g13gp vv,,<15,
a#3 >0v vp30+1g30<>,,#3^#
######p $ 0vg34"a"< > >vp
^<v> > ^ p3<>-#v_:05g-!|>:15g-!| $
> v^ < < < >^v-g52:< $
v _ >52*"eslaf",,vv|-g53:_ v
: ^-"#">#:< ##,,,,<<>:43p0 v0 p34<
>">"-!vgv< ^0p33g31p32-1g3<
^ <#g1|-g34_v#-g34_v#-g34"><v^"<<<<
v!<^<33>13g1v>03g1-v>03g1+03p$v $$
>^ _#-v 1>g1-1v>+13pv >03p v pp
^_:"^"^#|^g30 <3# $< $<>^33
^!-"<":<>"v"v^># p#$<> $^44
^ >#^#_ :" "-#v_ ^ > ^gg
v g34$< ^!<v"/":< >$3p$^>05g43p$ ^55
>,# |!-"\" :_$43g:">"-!|> ^$32
*v"x":< >-^ ^4g52<>:"^" -#v_^
5>-!#v_"ror"vv$p34g51:<>#| !-"<":<#|
^2,,, ,,"er"<>v #^^#<>05g43p$$^>^
>52*"eurt",,,,,#>15g4 3p$$$$ ^#
>:"v"\:"<"\: "^" -!#^_-!#^_-! ^
> ^
Explanation
If you're not familiar with the Befunge syntax and operation, check here.
Befunge is a stack-based language, but there are commands that allow one to write characters to the Befunge code. I take advantage of that in two places. First, I copy the entire input onto the Befunge board, but located a couple of lines below the actual written code. (Of course, this is never actually visible when the code runs.)
The other place is near the the upper-left:
######
a#
######
In this case, the area I've highlighted above is where I store a couple of coordinates. The first column in the middle row there is where I store the x-coordinate for the current "cursor position"; the second column is where I store the y-coordinate; the next two columns are for storing the x- and y-coordinate of the laser beam source when that is found; and the final column (with the 'a' character in it) is eventually overwritten to contain the current beam direction, which obviously changes as the beam's path is traced.
The program starts by placing (0,27) as the initial cursor position. Then input is read one character at a time and placed in the cursor position; newlines merely cause the y-coordinate to increase and the x-coordinate to go back to 0, just like a real carriage return. Eventually undef is read by the interpreter and that 0 character value is used to signal the end of input and move on to the laser iteration steps. When the laser character [<>^v] is read, that is also copied to the memory repository (over the 'a' character) and its coordinates are copied to the columns just to the left.
The end result of all of this is that the entire file is basically copied into the Befunge code, a little ways below the actual code traversed.
Afterwards, the beam location is copied back into the cursor locations, and the following iteration is performed:
Check for the current beam direction and increment or decrement the cursor coordinates appropriately. (I do this first to avoid having to deal with the corner case of the laser beam right on the first move.)
Read the character at that location.
If the character is "#", put newline and "false" on the stack, print, and end.
Compare it to all of the beam characters [<>^v]; if there's a match, also print "false\n" and end.
If the character is a space, empty the stack and continue.
If the character is a forward slash, get the beam direction onto the stack and compare it to each of the direction characters in turn. When one is found, the new direction is stored at that same spot in the code and the loop repeats.
If the character is a backslash, do basically the same thing as the above (except with the proper mapping for backslash).
If the character is 'x', we've hit the target. Print "true\n" and exit.
If the character is none of these, print "error\n" and exit.
If there's enough demand for it, I'll try to point out exactly where in the code all this is accomplished.
F#, 36 lines, very readable
Ok, just to get an answer out there:
let ReadInput() =
let mutable line = System.Console.ReadLine()
let X = line.Length
let mutable lines = []
while line <> null do
lines <- Seq.to_list line :: lines
line <- System.Console.ReadLine()
lines <- List.rev lines
X, lines.Length, lines
let X,Y,a = ReadInput()
let mutable p = 0,0,'v'
for y in 0..Y-1 do
for x in 0..X-1 do
printf "%c" a.[y].[x]
match a.[y].[x] with
|'v'|'^'|'<'|'>' -> p <- x,y,a.[y].[x]
|_ -> ()
printfn ""
let NEXT = dict [ '>', (1,0,'^','v')
'v', (0,1,'<','>')
'<', (-1,0,'v','^')
'^', (0,-1,'>','<') ]
let next(x,y,d) =
let dx, dy, s, b = NEXT.[d]
x+dx,y+dy,(match a.[y+dy].[x+dx] with
| '/' -> s
| '\\'-> b
| '#'|'v'|'^'|'>'|'<' -> printfn "false"; exit 0
| 'x' -> printfn "true"; exit 0
| ' ' -> d)
while true do
p <- next p
Samples:
##########
# / \ #
# #
# \ x#
# > / #
##########
true
##########
# v x #
# / #
# /#
# \ #
##########
false
#############
# # #
# > # #
# # #
# # x #
# # #
#############
false
##########
#/\/\/\ #
#\\//\\\ #
#//\/\/\\#
#\/\/\/x^#
##########
true
##########
# / \ #
# #
#/ \ x#
#\> / #
##########
false
##########
# / \#
# / \ #
#/ \ x#
#\^/\ / #
##########
false
Golfscript - 83 chars (mashup of mine and strager's)
The newline is just here for wrapping
:|'v^><'.{|?}%{)}?:$#=?{.[10|?).~)1-1]=$+
:$|=' \/x'?\[.\2^.1^'true''false']=.4/!}do
Golfscript - 107 chars
The newline is just there for clarity
10\:#?):&4:$;{0'>^<v'$(:$=#?:*>}do;
{[1 0&--1&]$=*+:*;[{$}{3$^}{1$^}{"true "}{"false"}]#*=' \/x'?=~5\:$>}do$
How it works.
First line works out the initial location and direction.
Second line steps through turning whenever the laser hits a mirror.
353 chars in Ruby:
314 277 chars now!
OK, 256 chars in Ruby and now I'm done. Nice round number to stop at. :)
247 chars. I can't stop.
223 203 201 chars in Ruby
d=x=y=-1;b=readlines.each{|l|d<0&&(d="^>v<".index l[x]if x=l.index(/[>^v<]/)
y+=1)};loop{c=b[y+=[-1,0,1,0][d]][x+=[0,1,0,-1][d]]
c==47?d=[1,0,3,2][d]:c==92?d=3-d:c==35?(p !1;exit):c<?x?0:(p !!1;exit)}
With whitespace:
d = x = y = -1
b = readlines.each { |l|
d < 0 && (d = "^>v<".index l[x] if x = l.index(/[>^v<]/); y += 1)
}
loop {
c = b[y += [-1, 0, 1, 0][d]][x += [0, 1, 0, -1][d]]
c == 47 ? d = [1, 0, 3, 2][d] :
c == 92 ? d = 3 - d :
c == 35 ? (p !1; exit) :
c < ?x ? 0 : (p !!1; exit)
}
Slightly refactored:
board = readlines
direction = x = y = -1
board.each do |line|
if direction < 0
x = line.index(/[>^v<]/)
if x
direction = "^>v<".index line[x]
end
y += 1
end
end
loop do
x += [0, 1, 0, -1][direction]
y += [-1, 0, 1, 0][direction]
ch = board[y][x].chr
case ch
when "/"
direction = [1, 0, 3, 2][direction]
when "\\"
direction = 3 - direction
when "x"
puts "true"
exit
when "#"
puts "false"
exit
end
end
Python
294 277 253 240 232 characters including newlines:
(the first character in lines 4 and 5 is a tab, not spaces)
l='>v<^';x={'/':'^<v>','\\':'v>^<',' ':l};b=[1];r=p=0
while b[-1]:
b+=[raw_input()];r+=1
for g in l:
c=b[r].find(g)
if-1<c:p=c+1j*r;d=g
while' '<d:z=l.find(d);p+=1j**z;c=b[int(p.imag)][int(p.real)];d=x.get(c,' '*4)[z]
print'#'<c
I had forgotten Python even had optional semicolons.
How it works
The key idea behind this code is using complex numbers to represent positions and directions. The rows are the imaginary axis, increasing downward. The columns are the real axis, increasing to the right.
l='>v<^'; a list of the laser symbols. The order is chosen so that the index of a laser direction character corresponds with a power of sqrt(-1)
x={'/':'^<v>','\\':'v>^<',' ':l}; a transformation table determining how the direction changes when the beam leaves different tiles. The tile is the key, and new directions are the values.
b=[1]; holds the board. The first element is 1 (evaluates as true) so that the while loop will run at least once.
r=p=0 r is the current row number of the input, p is the current position of the laser beam.
while b[-1]: stop loading board data when raw_input returns an empty string
b+=[raw_input()];r+=1 append the next line of input to the board and increment the row counter
for g in l: guess each laser direction in turn
c=b[r].find(g) set the column to the location of the laser or -1 if it's not in the line (or is pointing in a different direction)
if-1<c:p=c+1j*r;d=g if we found a laser, then set the current position p and direction d. d is one of the chars in l
After loading the board into b, the current position p and direction d have been set to those of the laser source.
while' '<d: space has a lower ASCII value than any of the direction symbols, so we use it as a stop flag.
z=l.find(d); index of the current direction char in the l string. z gets used later to both determine the new beam direction using the x table, and to increment the position.
p+=1j**z; increment the position using a power of i. For example, l.find('<')==2 -> i^2 = -1, which would move to the left one column.
c=b[int(p.imag)][int(p.real)]; read the char at the current position
d=x.get(c,' '*4)[z] look up the new direction for the beam in the transformation table. If the current char doesn't exist in the table, then set d to space.
print'#'<c print false if we stopped on anything other than the target.
This is was a direct port of Brian's solution to C#3, minus the console interactions.
This isn't an entry in the challenge since it isn't a complete program, I was just wondering how some of the F# constructs he used could be represented in C#.
bool Run(string input) {
var a = input.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
.First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
var NEXT = new[] {
new {d = '>', dx = 1, dy = 0, s = '^', b = 'v'},
new {d = 'v', dx = 0, dy = 1, s = '<', b = '>'},
new {d = '<', dx = -1, dy = 0, s = 'v', b = '^'},
new {d = '^', dx = 0, dy = -1, s = '>', b = '<'}
}.ToDictionary(x => x.d);
while (true) {
var n = NEXT[p.d];
int x = p.x + n.dx,
y = p.y + n.dy;
var d = a[y][x];
switch (d) {
case '/': d = n.s; break;
case '\\': d = n.b; break;
case ' ': d = p.d; break;
default: return d == 'x';
}
p = new {x, y, d};
}
}
Edit: After some experimentation, the following rather verbose search code:
int X = a[0].Length, Y = a.Length;
var p = new {x = 0, y = 0, d = 'v'};
for (var y = 0; y < Y; y++) {
for (var x = 0; x < X; x++) {
var d = a[y][x];
switch (d) {
case 'v': case '^': case '<': case '>':
p = new {x, y, d}; break;
}
}
}
has been replaced with some much more compact LINQ to Objects code:
var p = a.SelectMany((line, y) => line.Select((d, x) => new {x, y, d}))
.First(x => new[] {'v', '^', '<', '>'}.Contains(x.d));
F#, 255 chars (and still rather readable!):
Ok, after a night's rest, I improved this a lot:
let a=System.Console.In.ReadToEnd()
let w,c=a.IndexOf"\n"+1,a.IndexOfAny[|'^';'<';'>';'v'|]
let rec n(c,d)=
let e,s=[|-w,2;-1,3;1,0;w,1|].[d]
n(c+e,match a.[c+e]with|'/'->s|'\\'->3-s|' '->d|c->printfn"%A"(c='x');exit 0)
n(c,"^<>v".IndexOf a.[c])
Let's talk through it line by line.
First, slurp all the input into a big one-dimensional array (2D arrays can be bad for code golf; just use a 1D array and add/subtract the width of one line to the index to move up/down a line).
Next we compute 'w', the width of an input line, and 'c', the starting position, by indexing into our array.
Now let's define the 'next' function 'n', which takes a current position 'c' and a direction 'd' which is 0,1,2,3 for up,left,right,down.
The index-epsilon 'e' and the what-new-direction-if-we-hit-a-slash 's' are computed by a table. For example, if the current direction 'd' is 0 (up), then the first element of the table says "-w,2" which means we decrement the index by w, and if we hit a slash the new direction is 2 (right).
Now we recurse into the next function 'n' with (1) the next index ("c+e" - current plus epsilon), and (2) the new direction, which we compute by looking ahead to see what's in the array in that next cell. If the lookahead char is a slash, the new direction is 's'. If it's a backslash, the new direction is 3-s (our choice of encoding 0123 makes this work). If it's a space, we just keep going in the same direction 'd'. And if it's any other character 'c', then the game ends, printing 'true' if the char was 'x' and false otherwise.
To kick things off, we call the recursive function 'n' with the initial position 'c' and the starting direction (which does the initial encoding of direction into 0123).
I think I can probably still shave a few more characters off it, but I am pretty pleased with it like this (and 255 is a nice number).
Weighing in at 18203 characters is a Python solution that can:
cope with mirrors outside of the
'room'
calculate the trajectory when there is no 'room' on the basis of 2D limitations (the spec says lots about what has to be in the 'room' but not if the room has to exist)
report back on errors
It still needs tidied up somewhat and I do not know if 2D physics dictate that the beam cannot cross itself...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
The shortest code by character count to input a 2D representation of a board,
and output 'true' or 'false' according to the input.
The board is made out of 4 types of tiles:
# - A solid wall
x - The target the laser has to hit
/ or \ - Mirrors pointing to a direction (depends on laser direction)
v, ^, > or < - The laser pointing to a direction (down, up, right and left
respectively)
There is only one laser and only one target. Walls must form a solid rectangle
of any size, where the laser and target are placed inside. Walls inside the
'room' are possible.
Laser ray shots and travels from it's origin to the direction it's pointing. If
a laser ray hits the wall, it stops. If a laser ray hits a mirror, it is bounces
90 degrees to the direction the mirror points to. Mirrors are two sided, meaning
both sides are 'reflective' and may bounce a ray in two ways. If a laser ray
hits the laser (^v><) itself, it is treated as a wall (laser beam destroys the
beamer and so it'll never hit the target).
"""
SOLID_WALL, TARGET, MIRROR_NE_SW, MIRROR_NW_SE, LASER_DOWN, LASER_UP, \
LASER_RIGHT, LASER_LEFT = range(8)
MIRRORS = (MIRROR_NE_SW, MIRROR_NW_SE)
LASERS = (LASER_DOWN, LASER_UP, LASER_RIGHT, LASER_LEFT)
DOWN, UP, RIGHT, LEFT = range(4)
LASER_DIRECTIONS = {
LASER_DOWN : DOWN,
LASER_UP : UP,
LASER_RIGHT: RIGHT,
LASER_LEFT : LEFT
}
ROW, COLUMN = range(2)
RELATIVE_POSITIONS = {
DOWN : (ROW, 1),
UP : (ROW, -1),
RIGHT: (COLUMN, 1),
LEFT : (COLUMN, -1)
}
TILES = {"#" : SOLID_WALL,
"x" : TARGET,
"/" : MIRROR_NE_SW,
"\\": MIRROR_NW_SE,
"v" : LASER_DOWN,
"^" : LASER_UP,
">" : LASER_RIGHT,
"<" : LASER_LEFT}
REFLECTIONS = {MIRROR_NE_SW: {DOWN : LEFT,
UP : RIGHT,
RIGHT: UP,
LEFT : DOWN},
MIRROR_NW_SE: {DOWN : RIGHT,
UP : LEFT,
RIGHT: DOWN,
LEFT : UP}}
def does_laser_hit_target(tiles):
"""
Follows a lasers trajectory around a grid of tiles determining if it
will reach the target.
Keyword arguments:
tiles --- row/column based version of a board containing symbolic
versions of the tiles (walls, laser, target, etc)
"""
#Obtain the position of the laser
laser_pos = get_laser_pos(tiles)
#Retrieve the laser's tile
laser = get_tile(tiles, laser_pos)
#Create an editable starting point for the beam
beam_pos = list(laser_pos)
#Create an editable direction for the beam
beam_dir = LASER_DIRECTIONS[laser]
#Cache the number of rows
number_of_rows = len(tiles)
#Keep on looping until an ultimate conclusion
while True:
#Discover the axis and offset the beam is travelling to
axis, offset = RELATIVE_POSITIONS[beam_dir]
#Modify the beam's position
beam_pos[axis] += offset
#Allow for a wrap around in this 2D scenario
try:
#Get the beam's new tile
tile = get_tile(tiles, beam_pos)
#Perform wrapping
except IndexError:
#Obtain the row position
row_pos = beam_pos[ROW]
#Handle vertical wrapping
if axis == ROW:
#Handle going off the top
if row_pos == -1:
#Move beam to the bottom
beam_pos[ROW] = number_of_rows - 1
#Handle going off the bottom
elif row_pos == number_of_rows:
#Move beam to the top
beam_pos[ROW] = 0
#Handle horizontal wrapping
elif axis == COLUMN:
#Obtain the row
row = tiles[row_pos]
#Calculate the number of columns
number_of_cols = len(row)
#Obtain the column position
col_pos = beam_pos[COLUMN]
#Handle going off the left hand side
if col_pos == -1:
#Move beam to the right hand side
beam_pos[COLUMN] = number_of_cols - 1
#Handle going off the right hand side
elif col_pos == number_of_cols:
#Move beam to the left hand side
beam_pos[COLUMN] = 0
#Get the beam's new tile
tile = get_tile(tiles, beam_pos)
#Handle hitting a wall or the laser
if tile in LASERS \
or tile == SOLID_WALL:
return False
#Handle hitting the target
if tile == TARGET:
return True
#Handle hitting a mirror
if tile in MIRRORS:
beam_dir = reflect(tile, beam_dir)
def get_laser_pos(tiles):
"""
Returns the current laser position or an exception.
Keyword arguments:
tiles --- row/column based version of a board containing symbolic
versions of the tiles (walls, laser, target, etc)
"""
#Calculate the number of rows
number_of_rows = len(tiles)
#Loop through each row by index
for row_pos in range(number_of_rows):
#Obtain the current row
row = tiles[row_pos]
#Calculate the number of columns
number_of_cols = len(row)
#Loop through each column by index
for col_pos in range(number_of_cols):
#Obtain the current column
tile = row[col_pos]
#Handle finding a laser
if tile in LASERS:
#Return the laser's position
return row_pos, col_pos
def get_tile(tiles, pos):
"""
Retrieves a tile at the position specified.
Keyword arguments:
pos --- a row/column position of the tile
tiles --- row/column based version of a board containing symbolic
versions of the tiles (walls, laser, target, etc)
"""
#Obtain the row position
row_pos = pos[ROW]
#Obtain the column position
col_pos = pos[COLUMN]
#Obtain the row
row = tiles[row_pos]
#Obtain the tile
tile = row[col_pos]
#Return the tile
return tile
def get_wall_pos(tiles, reverse=False):
"""
Keyword arguments:
tiles --- row/column based version of a board containing symbolic
versions of the tiles (walls, laser, target, etc)
reverse --- whether to search in reverse order or not (defaults to no)
"""
number_of_rows = len(tiles)
row_iter = range(number_of_rows)
if reverse:
row_iter = reversed(row_iter)
for row_pos in row_iter:
row = tiles[row_pos]
number_of_cols = len(row)
col_iter = range(number_of_cols)
if reverse:
col_iter = reversed(col_iter)
for col_pos in col_iter:
tile = row[col_pos]
if tile == SOLID_WALL:
pos = row_pos, col_pos
if reverse:
offset = -1
else:
offset = 1
for axis in ROW, COLUMN:
next_pos = list(pos)
next_pos[axis] += offset
try:
next_tile = get_tile(tiles, next_pos)
except IndexError:
next_tile = None
if next_tile != SOLID_WALL:
raise WallOutsideRoomError(row_pos, col_pos)
return pos
def identify_tile(tile):
"""
Returns a symbolic value for every identified tile or None.
Keyword arguments:
tile --- the tile to identify
"""
#Safely lookup the tile
try:
#Return known tiles
return TILES[tile]
#Handle unknown tiles
except KeyError:
#Return a default value
return
def main():
"""
Takes a board from STDIN and either returns a result to STDOUT or an
error to STDERR.
Called when this file is run on the command line.
"""
#As this function is the only one to use this module, and it can only be
#called once in this configuration, it makes sense to only import it here.
import sys
#Reads the board from standard input.
board = sys.stdin.read()
#Safely handles outside input
try:
#Calculates the result of shooting the laser
result = shoot_laser(board)
#Handles multiple item errors
except (MultipleLaserError, MultipleTargetError) as error:
#Display the error
sys.stderr.write("%s\n" % str(error))
#Loop through all the duplicated item symbols
for symbol in error.symbols:
#Highlight each symbol in green
board = board.replace(symbol, "\033[01;31m%s\033[m" % symbol)
#Display the board
sys.stderr.write("%s\n" % board)
#Exit with an error signal
sys.exit(1)
#Handles item missing errors
except (NoLaserError, NoTargetError) as error:
#Display the error
sys.stderr.write("%s\n" % str(error))
#Display the board
sys.stderr.write("%s\n" % board)
#Exit with an error signal
sys.exit(1)
#Handles errors caused by symbols
except (OutsideRoomError, WallNotRectangleError) as error:
#Displays the error
sys.stderr.write("%s\n" % str(error))
lines = board.split("\n")
line = lines[error.row_pos]
before = line[:error.col_pos]
after = line[error.col_pos + 1:]
symbol = line[error.col_pos]
line = "%s\033[01;31m%s\033[m%s" % (before, symbol, after)
lines[error.row_pos] = line
board = "\n".join(lines)
#Display the board
sys.stderr.write("%s\n" % board)
#Exit with an error signal
sys.exit(1)
#Handles errors caused by non-solid walls
except WallNotSolidError as error:
#Displays the error
sys.stderr.write("%s\n" % str(error))
lines = board.split("\n")
line = lines[error.row_pos]
before = line[:error.col_pos]
after = line[error.col_pos + 1:]
symbol = line[error.col_pos]
line = "%s\033[01;5;31m#\033[m%s" % (before, after)
lines[error.row_pos] = line
board = "\n".join(lines)
#Display the board
sys.stderr.write("%s\n" % board)
#Exit with an error signal
sys.exit(1)
#If a result was returned
else:
#Converts the result into a string
result_str = str(result)
#Makes the string lowercase
lower_result = result_str.lower()
#Returns the result
sys.stdout.write("%s\n" % lower_result)
def parse_board(board):
"""
Interprets the raw board syntax and returns a grid of tiles.
Keyword arguments:
board --- the board containing the tiles (walls, laser, target, etc)
"""
#Create a container for all the lines
tiles = list()
#Loop through all the lines of the board
for line in board.split("\n"):
#Identify all the tiles on the line
row = [identify_tile(tile) for tile in line]
#Add the row to the container
tiles.append(row)
#Return the container
return tiles
def reflect(mirror, direction):
"""
Returns an updated laser direction after it has been reflected on a
mirror.
Keyword arguments:
mirror --- the mirror to reflect the laser from
direction --- the direction the laser is travelling in
"""
try:
direction_lookup = REFLECTIONS[mirror]
except KeyError:
raise TypeError("%s is not a mirror.", mirror)
try:
return direction_lookup[direction]
except KeyError:
raise TypeError("%s is not a direction.", direction)
def shoot_laser(board):
"""
Shoots the boards laser and returns whether it will hit the target.
Keyword arguments:
board --- the board containing the tiles (walls, laser, target, etc)
"""
tiles = parse_board(board)
validate_board(tiles)
return does_laser_hit_target(tiles)
def validate_board(tiles):
"""
Checks an board to see if it is valid and raises an exception if not.
Keyword arguments:
tiles --- row/column based version of a board containing symbolic
versions of the tiles (walls, laser, target, etc)
"""
found_laser = False
found_target = False
try:
n_wall, w_wall = get_wall_pos(tiles)
s_wall, e_wall = get_wall_pos(tiles, reverse=True)
except TypeError:
n_wall = e_wall = s_wall = w_wall = None
number_of_rows = len(tiles)
for row_pos in range(number_of_rows):
row = tiles[row_pos]
number_of_cols = len(row)
for col_pos in range(number_of_cols):
tile = row[col_pos]
if ((row_pos in (n_wall, s_wall) and
col_pos in range(w_wall, e_wall))
or
(col_pos in (e_wall, w_wall) and
row_pos in range(n_wall, s_wall))):
if tile != SOLID_WALL:
raise WallNotSolidError(row_pos, col_pos)
elif (n_wall != None and
(row_pos < n_wall or
col_pos > e_wall or
row_pos > s_wall or
col_pos < w_wall)):
if tile in LASERS:
raise LaserOutsideRoomError(row_pos, col_pos)
elif tile == TARGET:
raise TargetOutsideRoomError(row_pos, col_pos)
elif tile == SOLID_WALL:
if not (row_pos >= n_wall and
col_pos <= e_wall and
row_pos <= s_wall and
col_pos >= w_wall):
raise WallOutsideRoomError(row_pos, col_pos)
else:
if tile in LASERS:
if not found_laser:
found_laser = True
else:
raise MultipleLaserError(row_pos, col_pos)
elif tile == TARGET:
if not found_target:
found_target = True
else:
raise MultipleTargetError(row_pos, col_pos)
if not found_laser:
raise NoLaserError(tiles)
if not found_target:
raise NoTargetError(tiles)
class LasersError(Exception):
"""Parent Error Class for all errors raised."""
pass
class NoLaserError(LasersError):
"""Indicates that there are no lasers on the board."""
symbols = "^v><"
def __str__ (self):
return "No laser (%s) to fire." % ", ".join(self.symbols)
class NoTargetError(LasersError):
"""Indicates that there are no targets on the board."""
symbols = "x"
def __str__ (self):
return "No target (%s) to hit." % ", ".join(self.symbols)
class MultipleLaserError(LasersError):
"""Indicates that there is more than one laser on the board."""
symbols = "^v><"
def __str__ (self):
return "Too many lasers (%s) to fire, only one is allowed." % \
", ".join(self.symbols)
class MultipleTargetError(LasersError):
"""Indicates that there is more than one target on the board."""
symbols = "x"
def __str__ (self):
return "Too many targets (%s) to hit, only one is allowed." % \
", ".join(self.symbols)
class WallNotSolidError(LasersError):
"""Indicates that the perimeter wall is not solid."""
__slots__ = ("__row_pos", "__col_pos", "n_wall", "s_wall", "e_wall",
"w_wall")
def __init__(self, row_pos, col_pos):
self.__row_pos = row_pos
self.__col_pos = col_pos
def __str__ (self):
return "Walls must form a solid rectangle."
def __get_row_pos(self):
return self.__row_pos
def __get_col_pos(self):
return self.__col_pos
row_pos = property(__get_row_pos)
col_pos = property(__get_col_pos)
class WallNotRectangleError(LasersError):
"""Indicates that the perimeter wall is not a rectangle."""
__slots__ = ("__row_pos", "__col_pos")
def __init__(self, row_pos, col_pos):
self.__row_pos = row_pos
self.__col_pos = col_pos
def __str__ (self):
return "Walls must form a rectangle."
def __get_row_pos(self):
return self.__row_pos
def __get_col_pos(self):
return self.__col_pos
row_pos = property(__get_row_pos)
col_pos = property(__get_col_pos)
class OutsideRoomError(LasersError):
"""Indicates an item is outside of the perimeter wall."""
__slots__ = ("__row_pos", "__col_pos", "__name")
def __init__(self, row_pos, col_pos, name):
self.__row_pos = row_pos
self.__col_pos = col_pos
self.__name = name
def __str__ (self):
return "A %s was found outside of a 'room'." % self.__name
def __get_row_pos(self):
return self.__row_pos
def __get_col_pos(self):
return self.__col_pos
row_pos = property(__get_row_pos)
col_pos = property(__get_col_pos)
class LaserOutsideRoomError(OutsideRoomError):
"""Indicates the laser is outside of the perimeter wall."""
def __init__ (self, row_pos, col_pos):
OutsideRoomError.__init__(self, row_pos, col_pos, "laser")
class TargetOutsideRoomError(OutsideRoomError):
"""Indicates the target is outside of the perimeter wall."""
def __init__ (self, row_pos, col_pos):
OutsideRoomError.__init__(self, row_pos, col_pos, "target")
class WallOutsideRoomError(OutsideRoomError):
"""Indicates that there is a wall outside of the perimeter wall."""
def __init__ (self, row_pos, col_pos):
OutsideRoomError.__init__(self, row_pos, col_pos, "wall")
if __name__ == "__main__":
main()
A bash script to show off the colour error reporting:
#!/bin/bash
declare -a TESTS
test() {
echo -e "\033[1m$1\033[0m"
tput sgr0
echo "$2" | ./lasers.py
echo
}
test \
"no laser" \
" ##########
# x #
# / #
# /#
# \\ #
##########"
test \
"multiple lasers" \
" ##########
# v x #
# / #
# /#
# \\ ^ #
##########"
test \
"no target" \
" ##########
# v #
# / #
# /#
# \\ #
##########"
test \
"multiple targets" \
" ##########
# v x #
# / #
# /#
# \\ x #
##########"
test \
"wall not solid" \
" ##### ####
# v x #
# / #
# /#
# \\ #
##########"
test \
"laser_outside_room" \
" ##########
> # x #
# / #
# /#
# \\ #
##########"
test \
"laser before room" \
" > ##########
# x #
# / #
# /#
# \\ #
##########"
test \
"laser row before room" \
" >
##########
# x #
# / #
# /#
# \\ #
##########"
test \
"laser after room" \
" ##########
# x #
# / #
# /#
# \\ #
########## >"
test \
"laser row after room" \
" ##########
# x #
# / #
# /#
# \\ #
##########
> "
test \
"target outside room" \
" ##########
x # v #
# / #
# /#
# \\ #
##########"
test \
"target before room" \
" x ##########
# v #
# / #
# /#
# \\ #
##########"
test \
"target row before room" \
" x
##########
# v #
# / #
# /#
# \\ #
##########"
test \
"target after room" \
" ##########
# v #
# / #
# /#
# \\ #
########## x"
test \
"target row after room" \
" ##########
# v #
# / #
# /#
# \\ #
##########
x "
test \
"wall outside room" \
" ##########
# # v #
# / #
# /#
# \\ x #
##########"
test \
"wall before room" \
" # ##########
# v #
# / #
# /#
# \\ x #
##########"
test \
"wall row before room" \
" #
##########
# v #
# / #
# /#
# \\ x #
##########"
test \
"wall after room" \
" ##########
# v #
# / #
# /#
# \\ x #
########## #"
test \
"wall row after room" \
" ##########
# v #
# / #
# /#
# \\ x #
##########
#"
test \
"mirror outside room positive" \
" ##########
/ # / \\ #
# #
# \\ x#
# > / #
########## "
test \
"mirrors outside room negative" \
" ##########
\\ # v x #
# / #
# /#
# \\ #
##########"
test \
"mirror before room positive" \
" \\ ##########
# / \\ #
# #
# \\ x#
# > / #
########## "
test \
"mirrors before room negative" \
" / ##########
# v x #
# / #
# /#
# \\ #
##########"
test \
"mirror row before room positive" \
" \\
##########
# / \\ #
# #
# \\ x#
# > / #
########## "
test \
"mirrors row before room negative" \
" \\
##########
# v x #
# / #
# /#
# \\ #
##########"
test \
"mirror after row positive" \
" ##########
# / \\ #
# #
# \\ x#
# > / #
########## / "
test \
"mirrors after row negative" \
" ##########
# v x #
# / #
# /#
# \\ #
########## / "
test \
"mirror row after row positive" \
" ##########
# / \\ #
# #
# \\ x#
# > / #
##########
/ "
test \
"mirrors row after row negative" \
" ##########
# v x #
# / #
# /#
# \\ #
##########
/ "
test \
"laser hitting laser" \
" ##########
# v \\#
# #
# #
#x \\ /#
##########"
test \
"mirrors positive" \
" ##########
# / \\ #
# #
# \\ x#
# > / #
########## "
test \
"mirrors negative" \
" ##########
# v x #
# / #
# /#
# \\ #
##########"
test \
"wall collision" \
" #############
# # #
# > # #
# # #
# # x #
# # #
#############"
test \
"extreme example" \
" ##########
#/\\/\\/\\ #
#\\\\//\\\\\\ #
#//\\/\\/\\\\#
#\\/\\/\\/x^#
##########"
test \
"brian example 1" \
"##########
# / \\ #
# #
#/ \\ x#
#\\> / #
##########"
test \
"brian example 2" \
"##########
# / \\#
# / \\ #
#/ \\ x#
#\\^/\\ / #
##########"
The unittests used in development:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
from lasers import *
class TestTileRecognition(unittest.TestCase):
def test_solid_wall(self):
self.assertEqual(SOLID_WALL, identify_tile("#"))
def test_target(self):
self.assertEqual(TARGET, identify_tile("x"))
def test_mirror_ne_sw(self):
self.assertEqual(MIRROR_NE_SW, identify_tile("/"))
def test_mirror_nw_se(self):
self.assertEqual(MIRROR_NW_SE, identify_tile("\\"))
def test_laser_down(self):
self.assertEqual(LASER_DOWN, identify_tile("v"))
def test_laser_up(self):
self.assertEqual(LASER_UP, identify_tile("^"))
def test_laser_right(self):
self.assertEqual(LASER_RIGHT, identify_tile(">"))
def test_laser_left(self):
self.assertEqual(LASER_LEFT, identify_tile("<"))
def test_other(self):
self.assertEqual(None, identify_tile(" "))
class TestReflection(unittest.TestCase):
def setUp(self):
self.DIRECTION = LEFT
self.NOT_DIRECTIO
Ruby, 176 characters
x=!0;y=0;e="^v<>#x";b=readlines;b.map{|l|(x||=l=~/[v^<>]/)||y+=1};c=e.index(b[y][x])
loop{c<2&&y+=c*2-1;c>1&&x+=2*c-5;e.index(n=b[y][x])&&(p n==?x;exit);c^=' \/'.index(n)||0}
I used a simple state machine (like most posters), nothing fancy. I just kept whittling it down using every trick I could think of. The bitwise XOR used to change direction (stored as an integer in the variable c) was a big improvement over the conditionals I had in earlier versions.
I have a suspicion that the code that increments x and y could be made shorter. Here is the section of the code that does the incrementing:
c<2&&y+=c*2-1;c>1&&x+=(c-2)*2-1
Edit: I was able to shorten the above slightly:
c<2&&y+=c*2-1;c>1&&x+=2*c-5
The current direction of the laser c is stored as follows:
0 => up
1 => down
2 => left
3 => right
The code relies on this fact to increment x and y by the correct amount (0, 1, or -1). I tried rearranging which numbers map to each direction, looking for an arrangement that would let me do some bitwise manipulation to increment the values, because I have a nagging feeling that it would be shorter than the arithmetic version.
C# 3.0
259 chars
bool S(char[]m){var w=Array.FindIndex(m,x=>x<11)+1;var s=Array.FindIndex(m,x=>x>50&x!=92&x<119);var t=m[s];var d=t<61?-1:t<63?1:t<95?-w:w;var u=0;while(0<1){s+=d;u=m[s];if(u>119)return 0<1;if(u==47|u==92)d+=d>0?-w-1:w+1;else if(u!=32)return 0>1;d=u>47?-d:d;}}
Slightly more readable:
bool Simulate(char[] m)
{
var w = Array.FindIndex(m, x => x < 11) + 1;
var s = Array.FindIndex(m, x => x > 50 & x != 92 & x < 119);
var t = m[s];
var d = t < 61 ? -1 : t < 63 ? 1 : t < 95 ? -w : w;
var u = 0;
while (0 < 1)
{
s += d;
u = m[s];
if (u > 119)
return 0 < 1;
if (u == 47 | u == 92)
d += d > 0 ? -w - 1 : w + 1;
else if (u != 32)
return 0 > 1;
d = u > 47 ? -d : d;
}
}
The main waste of chars seems to be in finding the width of the map and the position of the laser source. Any ideas how to shorten this?
C + ASCII, 197 characters:
G[999],*p=G,w,z,t,*b;main(){for(;(*p++=t=getchar()^32)>=0;w=w|t-42?w:p-G)z=t^86?t^126?t^28?t^30?z:55:68:56:75,b=z?b:p;for(;t=z^55?z^68?z^56?z^75?0:w:-w:-1:1;z^=*b)b+=t;puts(*b^88?"false":"true");}
This C solution assumes an ASCII character set, allowing us to use the XOR mirror trick. It's also incredibly fragile - all the input lines must be the same length, for example.
It breaks under the 200 character mark - but dang it, still haven't beaten those Perl solutions!
Golfscript (83 characters)
Hello, gnibbler!
:\'><v^'.{\?}%{)}?:P#=?{:O[1-1\10?).~)]=P+
:P\=' \/x'?[O.2^.1^'true''false']=.4/!}do
Python - 152
Reads input from a file called "L"
A=open("L").read()
W=A.find('\n')+1
D=P=-1
while P<0:D+=1;P=A.find(">^<v"[D])
while D<4:P+=[1,-W,-1,W][D];D=[D,D^3,D^1,4,5][' \/x'.find(A[P])]
print D<5
To read from stdin replace the first line with this
import os;A=os.read(0,1e9)
If you need lowercase true/false change the last line to
print`D<5`.lower()
JavaScript - 265 Characters
Update IV - Odds are this will be the last round of updates, managed to save a couple more characters by switching to a do-while loop and rewriting the movement equation.
Update III - Thanks to the suggestion by strager in regards to removing Math.abs() and putting the variables in the global name space, that coupled with some rearranging of the variable assignments got the code down to 282 characters.
Update II - Some more updates to the code to remove the use of != -1 as well as some better use of variables for longer operations.
Update - When through and made some changes by creating a reference to the indexOf function (thanks LiraNuna!) and removing parenthesis that were not needed.
This is my first time doing a code golf so I'm not sure how much better this could be, any feed back is appreciated.
Fully minimized version:
a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}
Original version with comments:
character; length; loc; movement; temp;
function checkMaze(maze) {
// Use a shorter indexOf function
character = function(string) { return maze.indexOf(string); }
// Get the length of the maze
length = character("\n") + 1;
// Get the location of the laser in the string
character = maze[loc = temp = character("v") > 0 ? temp :
temp = character("^") > 0 ? temp :
temp = character("<") > 0 ? temp : character(">")];
// Get the intial direction that we should travel
movement = character == "<" ? -1 :
character == ">" ? 1 :
character == "^" ? -length : length;
// Move along until we reach the end
do {
// Get the current character
temp = movement == -1 | movement == 1;
character = maze[loc += movement = character == "\\" ? temp ? length * movement : movement > 0 ? 1 : -1 :
character == "/" ? temp ? -length * movement : movement > 0 ? 1 : -1 : movement];
// Have we hit a target?
temp = character == "x";
// Have we hit a wall?
} while (character != "#" ^ temp);
// temp will be false if we hit the target
return temp;
}
Web page to test with:
<html>
<head>
<title>Code Golf - Lasers</title>
<script type="text/javascript">
a;b;c;d;e;function f(g){a=function(a){return g.indexOf(a)};b=a("\n")+1;a=g[c=e=a("v")>0?e:e=a("^")>0?e:e=a("<")>0?e:a(">")];d=a=="<"?-1:a==">"?1:a=="^"?-b:b;do{e=d==-1|d==1;a=g[c+=d=a=="\\"?e?b*d:d>0?1:-1:a=="/"?e?-b*d:d>0?1:-1:d];e=a=="x"}while(a!="#"^e);return e}
</script>
</head>
<body>
<textarea id="maze" rows="10" cols="10"></textarea>
<button id="checkMaze" onclick="alert(f(document.getElementById('maze').value))">Maze</button>
</body>
</html>
House of Mirrors
Not an actual entry to the challenge, but I wrote a game based on this concept (not too long back).
It's written in Scala, open-source and available here:
It does a little bit more; deals with colors and various types of mirrors and devices, but version 0.00001 did exactly what this challenge asks. I have lost that version though and it was never optimised for character count anyway.
c (K&R) 339 necessary characters after more suggestions from strager.
The physicist in me noted that the propagation and reflection operations are time-reversal invariant, so this version, throws rays from the target and checks to see if the arrive at the laser emitter.
The rest of the implementation is very straight forward and is taken more or less exactly from my earlier, forward going effort.
Compressed:
#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;s(d,e,Z){for(;;)switch(m[x+=d][y+=e]){C'^':R 1==e;
C'>':R-1==d;C'v':R-1==e;C'<':R 1==d;C'#':C'x':R 0;C 92:e=-e;d=-d;C'/':c=d;
d=-e;e=-c;}}main(){while((c=getchar())>0)c==10?i=0,j++:(c==120?x=i,y=j:
i,m[i++][j]=c);puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");}
Uncompressed(ish):
#define R return
#define C case
#define Z x,y
int c,i,j,m[99][99],Z;
s(d,e,Z)
{
for(;;)
switch(m[x+=d][y+=e]){
C'^':
R 1==e;
C'>':
R-1==d;
C'v':
R-1==e;
C'<':
R 1==d;
C'#':
C'x':
R 0;
C 92:
e=-e;
d=-d;
C'/':
c=d;
d=-e;
e=-c;
}
}
main(){
while((c=getchar())>0)
c==10?i=0,j++:
(c==120?x=i,y=j:i,m[i++][j]=c);
puts(s(1,0,Z)|s(0,1,Z)|s(-1,0,Z)|s(0,-1,Z)?"true":"false");
}
There is no input validation, and bad input can send it into an infinite loop. Works properly with input no larger than 99 by 99. Requires a compiler that will link the standard library without including any of the headers. And I think I'm done, strager has me beat by a considerable stretch, even with his help.
I'm rather hoping someone will demonstrate a more subtle way to accomplish the task. There s nothing wrong with this, but it is not deep magic.
Ruby - 146 Chars
A=$<.read
W=A.index('
')+1
until
q=A.index(">^<v"[d=d ?d+1:0])
end
while d<4
d=[d,d^3,d^1,4,5][(' \/x'.index(A[q+=[1,-W,-1,W][d]])or 4)]
end
p 5>d
PostScript, 359 bytes
First attempt, lots of room for improvement...
/a[{(%stdin)(r)file 99 string readline not{exit}if}loop]def a{{[(^)(>)(<)(v)]{2
copy search{stop}if pop pop}forall}forall}stopped/r count 7 sub def pop
length/c exch def[(>)0(^)1(<)2(v)3>>exch get/d exch def{/r r[0 -1 0 1]d get
add def/c c[1 0 -1 0]d get add def[32 0 47 1 92 3>>a r get c get .knownget
not{exit}if/d exch d xor def}loop a r get c get 120 eq =
Haskell, 395 391 383 361 339 characters (optimized)
Still uses a generic state machine, rather than anything clever:
k="<>^v"
o(Just x)=x
s y(h:t)=case b of{[]->s(y+1)t;(c:_)->(c,length a,y)}where(a,b)=break(flip elem k)h
r a = f$s 0 a where f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"]of{Just r->r;_->"false"}where{i x y=lookup x.zip y;j=o.i c k;u=j[x-1,x+1,x,x];v=j[y,y,y-1,y+1];g t=f(j t,u,v)}
main=do{z<-getContents;putStrLn$r$lines z}
A readable version:
k="<>^v" -- "key" for direction
o(Just x)=x -- "only" handle successful search
s y(h:t)=case b of -- find "start" state
[]->s(y+1)t
(c:_)->(c,length a,y)
where (a,b)=break(flip elem k)h
r a = f$s 0 a where -- "run" the state machine (iterate with f)
f(c,x,y)=case i(a!!v!!u)"x /\\"["true",g k,g"v^><",g"^v<>"] of
Just r->r
_->"false"
where
i x y=lookup x.zip y -- "index" with x using y as key
j=o.i c k -- use c as index k as key; assume success
u=j[x-1,x+1,x,x] -- new x coord
v=j[y,y,y-1,y+1] -- new y coord
g t=f(j t,u,v) -- recurse; use t for new direction
main=do
z<-getContents
putStrLn$r$lines z
I believe in Code Reuse, I'd use one of your code as an API :).
puts Board.new.validate(input)
32 characters \o/... wohoooo
C++: 388 characters
#include<iostream>
#include<string>
#include<deque>
#include<cstring>
#define w v[y][x]
using namespace std;size_t y,x,*z[]={&y,&x};int main(){string p="^v<>",s;deque<string>v;
while(getline(cin,s))v.push_back(s);while(x=v[++y].find_first_of(p),!(x+1));int
i=p.find(w),d=i%2*2-1,r=i/2;do while(*z[r]+=d,w=='/'?d=-d,0:w==' ');while(r=!r,
!strchr("#x<^v>",w));cout<<(w=='x'?"true":"false");}
(318 without headers)
How it works:
First, all lines are read in, then, the laser is found. The following will evaluate to 0 as long as no laser arrow was found yet, and the same time assign to x the horizontal position.
x=v[++y].find_first_of(p),!(x+1)
Then we look what direction we found and store it in i. Even values of i are top/left ("decreasing") and odd values are bottom/right ("increasing"). According to that notion, d ("direction") and r ("orientation") are set. We index pointer array z with orientation and add the direction to the integer we get. The direction changes only if we hit a slash, while it remains the same when we hit a back-slash. Of course, when we hit a mirror, then we always change orientation (r = !r).
Groovy # 279 characers
m=/[<>^v]/
i={'><v^'.indexOf(it)}
n=['<':{y--},'>':{y++},'^':{x--},'v':{x++}]
a=['x':{1},'\\':{'v^><'[i(d)]},'/':{'^v<>'[i(d)]},'#':{},' ':{d}]
b=[]
System.in.eachLine {b<<it.inject([]) {r,c->if(c==~m){x=b.size;y=r.size;d=c};r<<c}}
while(d==~m){n[d]();d=a[b[x][y]]()}
println !!d
C#
1020 characters.
1088 characters (added input from console).
925 characters (refactored variables).
875 characters (removed redundant Dictionary initializer; changed to Binary & operators)
Made a Point not to look at anyone else's before posting. I'm sure it could be LINQ'd up a bit. And the whole FindLaser method in the readable version seems awfully fishy to me. But, it works and it's late :)
Note the readable class includes an additional method that prints out the current Arena as the laser moves around.
class L{static void Main(){
A=new Dictionary<Point,string>();
var l=Console.ReadLine();int y=0;
while(l!=""){var a=l.ToCharArray();
for(int x=0;x<a.Count();x++)
A.Add(new Point(x,y),l[x].ToString());
y++;l=Console.ReadLine();}new L();}
static Dictionary<Point,string>A;Point P,O,N,S,W,E;
public L(){N=S=W=E=new Point(0,-1);S.Offset(0,2);
W.Offset(-1,1);E.Offset(1,1);D();
Console.WriteLine(F());}bool F(){
var l=A[P];int m=O.X,n=O.Y,o=P.X,p=P.Y;
bool x=o==m,y=p==n,a=x&p<n,b=x&p>n,c=y&o>m,d=y&o<m;
if(l=="\\"){if(a)T(W);if(b)T(E);if(c)T(S);
if(d)T(N);if(F())return true;}
if(l=="/"){if(a)T(E);if(b)T(W);if(c)T(N);
if(d)T(S);if(F())return true;}return l=="x";}
void T(Point p){O=P;do P.Offset(p);
while(!("\\,/,#,x".Split(',')).Contains(A[P]));}
void D(){P=A.Where(x=>("^,v,>,<".Split(',')).
Contains(x.Value)).First().Key;var c=A[P];
if(c=="^")T(N);if(c=="v")T(S);if(c=="<")T(W);
if(c==">")T(E);}}
Readable Version (not quite the final golf version, but same premise):
class Laser
{
private Dictionary<Point, string> Arena;
private readonly List<string> LaserChars;
private readonly List<string> OtherChars;
private Point Position;
private Point OldPosition;
private readonly Point North;
private readonly Point South;
private readonly Point West;
private readonly Point East;
public Laser( List<string> arena )
{
SplitArena( arena );
LaserChars = new List<string> { "^", "v", ">", "<" };
OtherChars = new List<string> { "\\", "/", "#", "x" };
North = new Point( 0, -1 );
South = new Point( 0, 1 );
West = new Point( -1, 0 );
East = new Point( 1, 0 );
FindLaser();
Console.WriteLine( FindTarget() );
}
private void SplitArena( List<string> arena )
{
Arena = new Dictionary<Point, string>();
int y = 0;
foreach( string str in arena )
{
var line = str.ToCharArray();
for( int x = 0; x < line.Count(); x++ )
{
Arena.Add( new Point( x, y ), line[x].ToString() );
}
y++;
}
}
private void DrawArena()
{
Console.Clear();
var d = new Dictionary<Point, string>( Arena );
d[Position] = "*";
foreach( KeyValuePair<Point, string> p in d )
{
if( p.Key.X == 0 )
Console.WriteLine();
Console.Write( p.Value );
}
System.Threading.Thread.Sleep( 400 );
}
private bool FindTarget()
{
DrawArena();
string chr = Arena[Position];
switch( chr )
{
case "\\":
if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
{
OffSet( West );
}
else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
{
OffSet( East );
}
else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
{
OffSet( South );
}
else
{
OffSet( North );
}
if( FindTarget() )
{
return true;
}
break;
case "/":
if( ( Position.X == Position.X ) && ( Position.Y < OldPosition.Y ) )
{
OffSet( East );
}
else if( ( Position.X == Position.X ) && ( Position.Y > OldPosition.Y ) )
{
OffSet( West );
}
else if( ( Position.Y == Position.Y ) && ( Position.X > OldPosition.X ) )
{
OffSet( North );
}
else
{
OffSet( South );
}
if( FindTarget() )
{
return true;
}
break;
case "x":
return true;
case "#":
return false;
}
return false;
}
private void OffSet( Point p )
{
OldPosition = Position;
do
{
Position.Offset( p );
} while( !OtherChars.Contains( Arena[Position] ) );
}
private void FindLaser()
{
Position = Arena.Where( x => LaserChars.Contains( x.Value ) ).First().Key;
switch( Arena[Position] )
{
case "^":
OffSet( North );
break;
case "v":
OffSet( South );
break;
case "<":
OffSet( West );
break;
case ">":
OffSet( East );
break;
}
}
}
Perl 219
My perl version is 392 342 characters long (I had to handle the case of the beam hitting the laser):
Update, thanks Hobbs for reminding me of tr//, it's now 250 characters:
Update, removing the m in m//, changing the two while loops brought a few savings; there's now only one space required.
(L:it;goto L is the same length as do{it;redo}):
#b=map{($y,$x,$s)=($a,$-[0],$&)if/[<>^v]/;$a++;[split//]}<>;L:$_=$s;$x++if/>/;
$x--if/</;$y++if/v/;$y--if/\^/;$_=$b[$y][$x];die"true\n"if/x/;die"false\n"if
/[<>^v#]/;$s=~tr/<>^v/^v<>/if/\\/;$s=~tr/<>^v/v^></if/\//;goto L
I shaved some, but it barelyjust competes with some of these, albeit late.
It looks a little better as:
#!/usr/bin/perl
#b = map {
($y, $x, $s) = ($a, $-[0], $&) if /[<>^v]/;
$a++;
[split//]
} <>;
L:
$_ = $s;
$x++ if />/;
$x-- if /</;
$y++ if /v/;
$y-- if /\^/;
$_ = $b[$y][$x];
die "true\n" if /x/;
die "false\n" if /[<>^v#]/;
$s =~ tr/<>^v/^v<>/ if /\\/;
$s =~ tr/<>^v/v^></ if /\//;
goto L
Well... Honestly this should be self explanatory if you understand that the #b is an array arrays of characters in each line, and can read the simple regexp and tr statements.
F# - 454 (or thereabouts)
Bit late to the game, but can't resist posting my 2d attempt.
Update modified slightly. Now stops correctly if transmitter is hit. Pinched Brian's idea for IndexOfAny (shame that line is so verbose). I haven't actually managed to work out how to get ReadToEnd to return from the Console, so I'm taking that bit on trust...
I'm pleased with this answer, as though it is quite short, it is still fairly readable.
let s=System.Console.In.ReadToEnd() //(Not sure how to get this to work!)
let w=s.IndexOf('\n')+1 //width
let h=(s.Length+1)/w //height
//wodge into a 2d array
let a=Microsoft.FSharp.Collections.Array2D.init h (w-1)(fun y x -> s.[y*w+x])
let p=s.IndexOfAny[|'^';'<';'>';'v'|] //get start pos
let (dx,dy)= //get initial direction
match "^<>v".IndexOf(s.[p]) with
|0->(0,-1)
|1->(-1,0)
|2->(1,0)
|_->(0,1)
let mutable(x,y)=(p%w,p/w) //translate into x,y coords
let rec f(dx,dy)=
x<-x+dx;y<-y+dy //mutate coords on each call
match a.[y,x] with
|' '->f(dx,dy) //keep going same direction
|'/'->f(-dy,-dx) //switch dx/dy and change sign
|'\\'->f(dy,dx) //switch dx/dy and keep sign
|'x'->"true"
|_->"false"
System.Console.Write(f(dx,dy))