Code Golf: узнайте боксы ascii art
Придумал это некоторое время назад, выполняя некоторую работу с данными, хотя это создало бы хороший код для гольфа. Учитывая двумерный массив символов, содержащих прямоугольники ascii, создайте список координат и размеров для прямоугольников.
- Любой тривиально конвертируемый входной или выходной формат в порядке (например: char **, список строк, строки на стандартном входе, список из четырех целых чисел, структура, фиксированная сумма +/- для размера и т.д.).
- Точно так же вывод не должен быть в каком-либо конкретном порядке.
- У вас нет ничего полезного для недопустимых входных или неправильных прямоугольников, но вы не должны создавать корректные координаты для прямоугольника, который не находится на входе.
- Нет двух допустимых прямоугольников, разделяющих
+
(хотя +
может отображаться не только как часть прямоугольника)
- Вы можете предположить, что все прямоугольники не менее 3x3: каждая сторона имеет в ней
-
или |
.
Примеры:
" "
" +-+ | "
" | | \-"
" +-+ "
(2,1;3,3)
"+--+ +--+"
"| | | |"
"+--+ +--+"
(0,0;4,3), (6,0;4,3)
" +---+ "
"->|...| "
" +---+ "
(2,0;5,3)
"+-+ +--+ +--+"
"| | | | | |"
"+-+ | | + -+"
" | | "
" +--+ +-+ "
" +--+ | "
" +--+ +-+ "
(0,0;3,3), (4,0;4,5) # (2,5;4,2) is fine, but not needed
Ответы
Ответ 1
Perl, 167 165 159 символов
( 156 символов, если вы не считаете, что вы накладываете stdin на @a, просто удалите последние 3 символа и назначьте список строк, представляющих ваш вход, на @a)
Получает ввод из stdin. Новые строки не значимы, добавлены для удобства чтения. Обратите внимание на использование оператора +++
, P
map{$l=$i++;while($c=/\+-+\+/g){$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;
print"($x,$l;",$w+2,",$c)\n"if$a[$c+++$l]=~/^.{$x}\+-{$w}\+/}}@a=<>
Будьте либеральны в том, что вы принимаете версии, 170 символов
map{$l=$i++;while($c=/\+-*\+/g){pos=-1+pos;$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;
print"($x,$l;",$w+2,",$c)\n"if$a[$c+++$l]=~/^.{$x}\+-{$w}\+/}}@a=<>
Будьте консервативны в том, что вы принимаете версии, 177 символов
map{$l=$i++;while($c=/\+-+\+/g){$w=$+[0]-2-($x=$-[0]);
$c++while$a[$l+$c]=~/^.{$x}\|.{$w}\|/;print
"($x,$l;",$w+2,",$c)\n"if$c>1&&$a[$c+++$l]=~s/^(.{$x})\+(-{$w})\+/$1v$2v/}}@a=<>
Прокомментированная версия:
@a=<>; # slurp stdin into an array of lines
$l=0; # start counting lines from zero
map{ # for each line
while(/\+-+\+/g){ # match all box tops
$c=1; # initialize height
# x coordinate, width of box - sides
$w=$+[0]-2-($x=$-[0]);
# increment height while there are inner parts
# of a box with x and w coinciding with last top
# (look into next lines of array)
$c++ while $a[$l+$c]=~/^.{$x}\|.{$w}\|/;
# if there is a box bottom on line + height
# with coinciding x and w, print coords
# (after incrementing height)
print "($x,$l;",$w+2,",$c)\n"
if $a[$c+++$l]=~/^.{$x}\+-{$w}\+/
}
$l++ # line++
}@a
Мега-тест:
+--+ +-+ +-+ +++ +---+ +-+ +-+-+ +-++-+
|SO| | | | | +++ |+-+| | | | | | | || |
+--+ +-+-+-+ +++ ||+|| +-+ +-+-+ +-++-+
| | |+-+| | |
+-+-+-+ +---+ +-+
| | | |
+-+ +-+
++ +-+ ++ +-+ +- + +--+ +--+ +--+
|| +-+ ++ +-+-+ | | | | | | |
++ | | | | | | | | |
+-+ +--+ + -+ +--+ +--+
Ответ 2
Ruby - 306 260 245 228 168
# 228 chars
g=->(s,u='-'){o=[];s.scan(/\+#{u}+\+/){o<<[$`,$`+$&].map(&:size)};o}
b=t.map{|i|i.split''}.transpose.map{|s|g[s*'','\|']}
(1...t.size).map{|i|i.times{|j|(g[t[i]]&g[t[j]]).map{|x,y|p [x,j,y-x,i-j+1]if(b[x]&b[y-1]&[[j,i+1]])[0]}}}
производит
[0, 0, 3, 3]
[4, 1, 4, 3]
[10, 3, 3, 3]
при t =
["+-+ +--+",
"| | +--+ | |",
"+-+ | | + -+",
" +--+ +-+ ",
" +--+ | | ",
" +--+ +-+ "]
Пояснение:
# function returns info about all inclusions of "+---+" in string
# " +--+ +-+" -> [[2,5],[7,9]]
g=->(s,u='-'){o=[];s.scan(/\+#{u}+\+/){o<<[$`,$`+$&].map(&:size)};o}
# mapping transposed input with this function
b=t.map{|i|i.split''}.transpose.map{|s|g[s*'','\|']}
# earlier here was also mapping original input, but later was merged with "analyse"
# "analyse"
# take each pair of lines
(1...t.size).map{|i|i.times{|j|
# find horizontal sides of the same length on the same positions
(g[t[i]]&g[t[j]]).map{|x,y|
# make output if there are correct vertical sides
p [x,j,y-x,i-j+1]if(b[x]&b[y-1]&[[j,i+1]])[0]
}
}}
# yeah, some strange +/-1 magick included ,.)
И более прямолинейное решение с 168-символами!
t.size.times{|i|t[0].size.times{|j|i.times{|k|j.times{|l|p [l,k,j-l+1,i-k+1]if
t[k..i].map{|m|m[j]+m[l]}*''=~/^\+\+\|+\+\+$/&&t[i][l..j]+t[k][l..j]=~/^(\+-+\+){2}$/}}}}
Ответ 3
Perl - 223 222 216
Версия для гольфа (новые строки не значимы):
$y=0;sub k{$s=$-[0];"($s,%i;".($+[0]-$s).",%i)"}while(<>){while(/\+-+\+/g){
if(exists$h{&k}){[email protected],sprintf k,@{$h{&k}};delete$h{&k}}else{$h{&k}=[$y,2]}}
while(/\|.+?\|/g){++${$h{&k}}[1]if exists$h{&k}}++$y}print"@o\n"
Пожилая версия для игры в гольф:
# y starts at line zero.
$y = 0;
# Abuse Perl dynamic scoping rules
# to get a key for the hash of current rectangles,
# which indexes rectangles by x and width,
# and is also used as a format string.
sub k {
# The start of the current match.
$s = $-[0];
# $+[0] is the end of the current match,
# so subtract the beginning to get the width.
"($s,%i;" . ($+[0] - $s) . ",%i)"
}
# Read lines from STDIN.
while (<>) {
# Get all rectangle tops and bottoms in this line.
while (/\+-+\+/g) {
# If line is a bottom:
if (exists $h{&k}) {
# Add to output list and remove from current.
push @o, sprintf k, @{$h{&k}};
delete $h{&k}
# If line is a top:
} else {
# Add rectangle to current.
$h{&k} = [$y, 2]
}
}
# Get all rectangle sides in this line.
while (/\|.+?\|/g) {
# Increment the height of the corresponding
# rectangle, if one exists.
++${$h{&k}}[1] if exists $h{&k}
}
# Keep track of the current line.
++$y
}
# Print output.
print join", ",@o
Обратите внимание, что это не обрабатывает нежелательные вертикальные столбцы слева от прямоугольников, а именно:
+--+ +--+
| | | | |
+--+ +--+
Будет неверно выдавать высоту 2 для обоих. Это происходит из-за того, что шаблон /\|.+?\|/g
начинает поиск с начала строки. У кого-нибудь есть предложение, как это исправить?
Ответ 4
JavaScript — 156 символов *
Также на http://jsfiddle.net/eR5ee/4/ (используйте ссылку только при использовании Firefox или Chrome) или http://jsfiddle.net/eR5ee/5/ (адаптировано для Safari и Opera):
var A = [
"+-+ +--+ +--+",
"| | | | | |",
"+-+ | | + -+",
" | | ",
" +--+ +-+ ",
" +--+ | ",
" +--+ +-+ "
]; // not counted
for(y=A.length;--y;)for(;m=/\+-*\+/g(A[y]);){
for(w=m[0].length,z=y;A[--z][x=m.index]+A[z][x+w-1]=="||";);
/^\+-*\+$/(A[z].substr(x,w))&&alert([x,z,w,y-z+1])}
- За исключением символов новой строки и пробелов, которые совершенно не нужны.
- По-видимому, Firefox и Chrome сохраняют lastIndex первого регулярного выражения. Для сохранения Safari и Opera из бесконечного цикла требуется еще четыре символа. Чтобы заставить Internet Explorer работать, потребуется еще четырнадцать символов для исправления как выше, так и ошибки "Функция ожидается". По-видимому, "... метод exec регулярного выражения может быть вызван... косвенно (с
regexp(str)
)" (цитируется из документации Mozilla) не относится к IE.
Код обнаруживает все прямоугольники 2x2 и больше, если ни одно прямоугольное дно не касается ни одного другого верхнего или нижнего прямоугольника или знака плюс или минус и не перекрывается.
Порядок номеров в каждом окне предупреждения (который соответствует прямоугольнику) остается слева, сверху, шириной, высотой. Код делает ошибку, если прямоугольник продолжается сверху, но все необходимые координаты уже были выведены (из спецификации: "Вам не нужно (sic) ничего полезного для недопустимых входных или искаженных прямоугольников..." )
Так как большинство основных веб-браузеров реализуют тег canvas, еще в нескольких строках кода, рисование обнаруженных прямоугольников на экране возможно. http://jsfiddle.net/MquqM/6/ работает во всех браузерах, кроме Internet Explorer и Opera.
Изменить: исключено ненужное присвоение переменной
Редактирование 2: избегайте бросать ошибки с полностью допустимым вводом (-y вместо y--), проясните конкретные случаи, когда код обрабатывает
Ответ 5
C ( 204 186 символов)
#include<stdio.h>
char H=7,W=14,*S =
"+-+ +--+ +--+"
"| | | | | |"
"+-+ | | + -+"
" | | "
" +--+ +-+ "
" +--+ | "
" +--+ +-+ ";
void main(){
#define F(a,r,t)if(*c==43){while(*(c+=a)==r);t}
char*c,*o,*e=S;while(*(c=e++))
F(1,45,F(W,'|',o=c;F(-1,45,F(-W,'|',c==e-1?
printf("%i,%i %i,%i\n",(c-S)%W,(c-S)/W,(o-c)%W+1,(o-c)/W+1):0;))))
}
Счетчик символов - это тело main(). Этот код будет перемещаться по строке с e до тех пор, пока он не достигнет верхнего левого угла потенциального прямоугольника. Затем он проверяет края с помощью c и использует o для отслеживания нижнего правого угла.
Вывод программы:
0,0 3,3
4,0 4,5
2,5 4,2
Ответ 6
Scala 2.8 - 283 273 269 257
val a = Seq(
"+-+ +--+ +--+",
"| | | | | |",
"+-+ | | + -+",
" | | ",
" +--+ +-+ ",
" +--+ | ",
" +--+ +-+ "
)
// begin golf count
val (w,h) = (a(0).size-1,a.size-1)
for (
x <- 0 to w;
y <- 0 to h;
u <- x+2 to w;
v <- y+2 to h;
if Set(a(y)(x),a(v)(x),a(y)(u),a(v)(u)) == Set(43)
&& (x+1 to u-1).forall(t => (a(y)(t)<<8|a(v)(t)) == 11565)
&& (y+1 to v-1).forall(t => (a(t)(x)<<8|a(t)(u)) == 31868)
) yield (x,y,u-x+1,v-y+1)
// end golf count
имеет значение:
Vector((0,0,3,3), (4,0,4,5))
Выражение for
оценивает ответ (объект Vector), поэтому я подсчитал только эту часть (удаленные пробелы). Дайте мне знать, правильно ли это считать.
Как это работает
Координаты всех возможных прямоугольников (фактически, только >= 3x3) генерируются выражением for
. Эти координаты фильтруются, ища +, - и | по краям и углам всех прямоугольников (часть if
выражения for
).
Ответ 7
Python 2.6 - 287 263 254
a = [
"+-+ +--+ +--+",
"| | | | | |",
"+-+ | | + -+",
" | | ",
" +--+ +-+ ",
" +--+ | ",
" +--+ +-+ "
]
l=len
r=range
w,h=l(a[0]),l(a)
[(x,y,u,v)for x in r(0,w)for y in r(0,h)for u in r(x+2,w)for v in r(y+2,h)if a[y][x]==a[v][x]==a[y][u]==a[v][u]=='+' and a[y][x+1:u]+a[v][x+1:u]=="-"*2*(u-x-1)and l([c for c in r(y+1,v-y)if a[c][x]==a[c][u]=='|'])==v-y-1]
оценивается как:
[(0, 0, 3, 3), (4, 0, 4, 5)]
Ответ 8
Python 2.6 (251 символ)
Я прихожу немного поздно, во всяком случае, немного веселья. Python, используя регулярные выражения. Чтобы сохранить оператор печати и оставаться короче, чем Fredb219, это ничего не будет печатать, если вы запустите его как script, но набрав по одной строке за раз в интерпретаторе, он покажет результат. Не очень солидный, он не будет обрабатывать вложенные ящики и большинство случаев, более сложных, чем те, которые даются DavidX. Не проводили тестирование, но я думаю, что он может показать результаты в неправильном порядке, если произойдет что-то "странное".
import re
l,a,o=s.index("\n")+1,re.finditer,sorted
o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)
Ввод - это одна строка, строки (одинаковая длина), разделенные символом новой строки. Результатом являются строковые срезы сверху и снизу для каждого "хорошего" поля, начиная с левого верхнего угла. Он также позволяет "сломанные" коробки (т.е. С некоторым пространством посередине одной стороны, не без одной цельной стороны). Это был всего лишь способ исправить нежелательное поведение, создав много новых побочных эффектов!:-)
ввод:
>>>s = """+-+ +--+ +--+
| | | | | |
+-+ | | + -+
| |
+--+ +-+
+--+ |
+--+ +-+ """
или
>>>s = "+-+ +--+ +--+\n| | | | | |\n+-+ | | + -+\n | | \n +--+ +-+ \n +--+ | \n +--+ +-+ "
то
>>>import re
>>>l,a,o=s.index("\n")+1,re.finditer,sorted
>>>o(o(set((m.start(),m.end())for m in a(r'\+-* *-*\+',s)for n in a(r'\|.+?\|',s)if(m.start()%l,m.end()%l)==(n.start()%l,n.end()%l)if m.start()+l==n.start()or m.start()-l==n.start())),key=lambda x:x[0]%l)
выход:
[(0, 3), (30, 33), (4, 8), (64, 68), (10, 14), (40, 44)]
так (0,3) верхняя часть 1-го ящика (30,33) снизу того же поля, (4,8) вверху второго ящика и т.д.
Ответ 9
F #, 297 символов
Своего рода, но просто.
let F a=
for x=0 to Array2D.length1 a-1 do
for y=0 to Array2D.length2 a-1 do
if a.[x,y]='+' then
let mutable i,j=x+1,y+1
while a.[i,y]<>'+' do i<-i+1
while a.[x,j]<>'+' do j<-j+1
printfn"(%d,%d;%d,%d)"x y (i-x+1)(j-y+1)
a.[i,y]<-' '
a.[x,j]<-' '
a.[i,j]<-' '
Ищите плюса. Найдите тот, который находится справа от него. Найдите ниже. Распечатайте эту информацию о прямоугольнике и "вычеркните" плюсы, которые мы уже использовали. Поскольку каждый плюс является только частью одного правильного прямоугольника, это все, что нам нужно сделать.
Ответ 10
XQuery (304 символа)
Вот мое решение:
declare variable $i external;let$w:=string-length($i[1]),$h:=count($i)for$y in 1 to$h,$x in 1 to$w,$w in 2 to$w+1 -$x,$h in 1 to$h where min(for$r in (0,$h),$s in 1 to$h return (matches(substring($i[$y+$r],$x,$w),'^\+-*\+$'),matches(substring($i[$y+$s],$x,$w),'^|.*|$')))return ($x -1,$y -1,$w,$h+1,'')
Вы можете запустить это (с помощью XQSharp), установив переменную $i
в качестве строк ввода
>XQuery boxes.xq "i=(' +-+','+-+-+','| | ','+-+ ')" !method=text
2 0 3 2 0 1 3 3
Я полагаю, можно утверждать, что declare variable $i external;
просто устанавливает ввод и поэтому не добавляет к счету, и в этом случае 275 символов