Skip to content

Instantly share code, notes, and snippets.

@kreeger
Last active December 10, 2015 23:55
Show Gist options
  • Save kreeger/4511772 to your computer and use it in GitHub Desktop.
Save kreeger/4511772 to your computer and use it in GitHub Desktop.
XML => acrosslite.
#!/usr/bin/env ruby
require 'nokogiri'
require 'ostruct'
# Read in the file, convert to UTF-8 if needed, and parse with Nokogiri.
glob = ARGV[0]
exit if glob.nil?
Dir[glob].each do |filename|
next if filename =~ /^\./
encoding = `file --mime-encoding -b #{filename}`.chomp
data = File.open(filename, "r:#{encoding}") { |f| f.read }
data = data.unpack('C*').pack('U*') if data.encoding == 'US-ASCII'
data.encode!('UTF-8')
noko = Nokogiri::XML::Document.parse(data)
# Prep our result hash.
result = {}
# Pull out the width and height. We'll use these.
width, height = %w(Width Height).map do |node|
noko.search(node).first['v'].to_i
end
# Get the title and author.
result[:author] = %w(Title Author).map do |node|
noko.search(node).first['v']
end
result[:author] = result[:author].join(' ')
# Map out the black squares in the layout grid.
answer = noko.search('AllAnswer').first['v']
result[:layout] = answer.scan(%r(.{#{width}})).map do |row|
row.split('').map { |cell| cell =~ /-/ ? '-01' : '000' }
end
# Get the "solution" block from the answers.
result[:solution] = answer.scan(%r(.{#{width}})).map do |row|
row.gsub(/-/, ' ')#.split(' ').join(' ')
end
# Create a list of clue objects.
%w(across down).each do |direction|
clues = noko.search(direction).first.children.reject do |child|
child.attributes.empty?
end
result[direction.to_sym] = clues.map do |a|
OpenStruct.new({
number: a.attributes['cn'].value.to_i,
text: a.attributes['c'].value,
position: a.attributes['n'].value.to_i
})
end
end
# Index the clue objects by their position.
positions = {}
%w(across down).each do |direction|
positions.merge! result[direction.to_sym].group_by { |clue| clue.position }
end
# Go through each square in the grid and place the numbers in the positions they belong in.
counter = 1
result[:layout] = result[:layout].map do |row|
new_row = []
row.each do |cell|
unless cell =~ /-01/
if positions.keys.include?(counter)
cell = '%03d' % positions[counter].first.number
else
cell = '000'
end
end
counter += 1
new_row << cell
end
new_row
end
# Textify the output.
output = []
result.each do |name, value|
output << name.to_s
if name == :layout
output << value.map { |row| row.join('') }.join("\n")
elsif name == :across || name == :down
value.each do |val|
val.text.gsub!(/%27/, "'")
val.text.gsub!(/%22/, '"')
output << "#{'%02d' % val.number}|#{val.text}"
end
else
output << value
end
end
new_filename = filename.gsub(File.extname(filename), '.txt')
File.open(new_filename, 'w') { |f| f.write output.join("\n") }
puts "#{filename} converted to #{new_filename}."
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment