10, 10, 10… надеюсь?


15

Предисловие

Поскольку сегодня я стрелял в стрельбу из лука 900 раундом ранее (10 заканчивается по 6 стрел в конце и 10 заканчивается по 3 стрелы в конце, всего 90 стрел и максимальный счет 900), я подумал об этом испытании.

В стрельбе из лука (при условии, что вы стреляете по целевому лицу, предоставленному FITA [листу бумаги, на который вы стреляете)), для каждой стрелки вы можете получить максимальный балл 10. Целевая грань содержит 10 или 11 колец с уменьшающимся диаметром, вложенные друг в друга Начиная с внутреннего кольца, они отсчитываются от 10 баллов до одного балла (а в случае 11 колец есть вторичное самое внутреннее кольцо, которое считается как «X», которое оценивается как 10, но используется в случаях разрыва связи как чем выше значение). Заметим:

FITA Целевая оценка

Конечно, я имею в виду оценку FITA Metric, как показано на иллюстрации выше. Если вы присмотритесь, вы можете увидеть самое внутреннее кольцо, которое представляет собой заштрихованную пунктирную линию, счет которой не отмечен. Это «Х», о котором я говорил, но вам не придется обращать на это внимание, если только вы не будете бороться за бонус.

Вызов

Создайте функцию (или полную программу, если язык не поддерживает функции), которая получает идеально квадратное изображение в качестве входных данных (или имя файла изображения, если это необходимо), содержащее некоторое количество зеленых (HEX # 00FF00, RGB (0, 255, 0)) точек некоторого размера и возвращает счет. Изображение может содержать данные, отличные от зеленых точек , но зеленый цвет всегда будет иметь одинаковый оттенок.

Вы можете себе представить, что квадратное изображение представляет целевую грань, причем самое наружное кольцо соприкасается в 4 точках (верхний центр, нижний центр, правый центр, левый центр). Представленная целевая грань всегда будет иметь одинаковую пропорцию, причем все кольца имеют ширину ровно 1/20 ширины входного целевого изображения. В качестве примера, учитывая входное изображение с входными размерами 400 на 400 пикселей, вы можете предположить, что каждое кольцо имеет внутреннюю ширину 20 пикселей, как показано ниже:

Дрянной пример иллюстрации

Разъяснения

  • Если дотронуться до двух отдельных колец, считается высшее из двух колец
  • Вам не нужно автоматически учитывать промахи или случай «х», если только вы не пытаетесь получить бонус
  • Вы можете предположить, что зеленые круги не перекрываются
  • Вы также можете предположить, что на изображении отсутствуют другие пиксели этого зеленого цвета.
  • Изображение будет в формате PNG, JPEG или PPM (на ваш выбор)
  • Библиотеки внешней обработки изображений разрешены, если они созданы до публикации этого вопроса
  • Вы можете предположить, что все зеленые круги на одной цели будут иметь одинаковый диаметр
  • Если вы снимаете (ха) на бонус перекрывающихся кругов, вы можете предположить, что хотя бы один круг на изображении не имеет другого перекрывающегося круга.
  • Стандартные лазейки запрещены

Контрольные примеры

В следующих двух случаях каждый должен набрать 52 (или в случае бонусов 52 с 1 'x' и 1 промахом):

И этот последний контрольный пример должен набрать 25 :

бонус

  • -25 байт, если вы также возвращаете количество пропусков (вне любого из колец)
  • -30 байт, если вы также возвращаете количество X (предположим, что самый внутренний x равен 3/100-й ширины изображения, а 10 - 2/100-й ширины изображения. Пропорции 1-9 остаются неизменными)
  • Количество байтов -35%, если вы учитываете перекрывающиеся круги

Это код гольф, поэтому выигрывает наименьшее количество байтов. Веселиться!


«30 заканчивается на 3 стрелки на конце, всего 30 стрел»? Разве это не должно быть 90 стрел?
DavidC

@DavidCarraher Я понял это правильно, когда я отправил. Исправлено
сумасшедший

Какие форматы изображений мы можем использовать? PNG? PPM? Наш собственный пользовательский формат? (Я бы взял первые два, но не третий, но только для пояснения.)
Ручка двери

Скажем, просто JPEG или PNG для простоты @ Doorknob 冰
дрянной

1
Я думаю, что самый сложный бонус - это тот, у которого меньше всего наград.
Джастин

Ответы:


4

Обработка 2, 448-25 = 423 байта

int x,y,w,b,v,c,m;color g;PImage i;void setup(){i=loadImage("f.png");w=i.width;size(w,w);g=#00ff00;image(i,0,0);b=v=x=y=c=m=0;loadPixels();while(y*w+x<w*w){if(pixels[y*w+x]==g){f(y,x);if(v>=0)c+=v;else m++;}v=-1;x++;if(x==w){x=0;y++;}}println(c+" "+m);}void f(int k,int l){pixels[k*w+l]=color(0);if(pixels[(k+1)*w+l]==g)f(k+1,l);if(pixels[k*w+l+1]==g)f(k,l+1);if(pixels[k*w+l-1]==g)f(k,l-1);k-=w/2;l-=w/2;b=10-(int)(sqrt(k*k+l*l)/(w/20));if(b>v)v=b;}

Считывает из файла изображения f цикл по пикселям, пока не станет зеленым, а затем заливка заполняет круг, определяющий точку, которая находится ближе всего к центру. Затем добавляет этот счет к общему количеству. если оценка отрицательная, она добавляется к счетчику пропущенных.

Программа выведет 2 числа, первое - это счет, а второе - количество пропущенных.

  int x,y,w,b,v,c,m;
  color g;
  PImage i;
void setup()
{
  i=loadImage("f.png");
  w=i.width;
  size(w,w);
  g=#00ff00;
  image(i,0,0);
  b=v=x=y=c=m=0;  
  loadPixels();
  while(y*w+x<w*w)
  {
    if(pixels[y*w+x]==g)
    {
      f(y,x);
      if(v>=0)c+=v;
      else m++;
    }
    v=-1;
    x++;
    if(x==w){x=0;y++;}
  }
  print(c+" "+m);
}

void f(int k,int l)
{
  pixels[k*w+l]=color(0);
 if(pixels[(k+1)*w+l]==g)f(k+1,l);
 if(pixels[k*w+l+1]==g)f(k,l+1);
 if(pixels[k*w+l-1]==g)f(k,l-1); 
 k-=w/2;
 l-=w/2;
 b=10-(int)(sqrt(k*k+l*l)/(w/20));
 if(b>v)v=b;
}

Вы можете получить обработку здесь


4

Perl 5 + GD: 225 - 25 = 200

Изменить: нашел причину неправильного чтения пикселей в индексированных PNG и применил обходной путь. По какой-то причине в библиотеке GD значения зеленого пикселя читаются как (4,254,4). Я не уверен, относится ли это к файлам PNG, включенным в вопрос. Разрывы строк могут быть удалены в коде ниже.

use GD;$k=newFromPng GD::Image'-',1;
sub v{/ /;10-int((($'-@x/2)**2+($`-@x/2)**2)**.5/@x*20)}
map{v>0?($r+=v):$%++,fill$k @c,0if 65280==getPixel$k @c=split
}sort{v($_=$b)- v$_=$a}map{//;map"$_ $'",@x}@x=0..width$k-1;
print"$r $%"

Принимает изображение PNG на вход и печатает 2 значения: Количество точек и промахов. Например:

perl arch.pl <arch52.png
52 1

Последнее изменение:

В режиме истинного цвета, который мне в любом случае понадобился, индексы цвета используются getPixelи fillявляются просто целочисленными значениями RGB, поэтому нет необходимости использовать rgbи colorAllocateдля преобразования в и из этих индексов.

Объяснение:

  • Создать список всех координат пикселей (как разделенные пробелом пары целых чисел).
  • Сортировка по потенциальному баллу (использование sub vкоторого пропускает параметр $_вместо стандартных параметров, поскольку он короче).
  • Для каждого пикселя, начиная с наивысшего балла, если он зеленый, добавьте к результату и залейте его местоположение черным.

Это не изображения; Ответ @ bubalou правильно читайте цвета как # 00FF00
globby

@globby Я знаю, что цвета на изображении правильные (я проверял это с помощью программного обеспечения для редактирования изображений), но, возможно, есть и та же метаинформация для обрезки цветового пространства.
nutki

возможно. Это странно, хотя
грязный

3

Haskell - 579-25 = 554 603-25-30 576-25-30 = 521 байт

Стратегия:

  • Составьте список (d, x, y) троек для всех пикселей (d - расстояние до центра)
  • сортировать список по расстоянию
  • начиная с наибольшего расстояния: если пиксель - единственный зеленый пиксель в небольшом районе, оставьте это расстояние в списке L, в противном случае затемните его
  • рассчитать счет из списка расстояний L

Вывод тройной (оценка, промахи, X), например, (52,1,1)для тестового изображения.

Программа может не работать, если пиксель круга, ближайшего к центру, находится в пределах 3 пикселей от другого круга.

import Data.List
import Codec.Picture
import Codec.Picture.RGBA8
import Codec.Picture.Canvas
z=fromIntegral
f(e,x,y)(v,h)|and$j x y:[not$j a b|a<-[x-3..x+3],b<-[y-3..y+3],not(a==x&&b==y)]=(v,e:h)|1<2=(setColor x y(PixelRGBA8 0 0 0 0)v,h)
 where j n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
d k r(h,i,j)|r>10*k=(h,i+1,j)|r<k*3/5=(h+10,i,j+1)|1<2=(10-(floor$r/k)+h,i,j)
main=do
 i<-readImageRGBA8 "p.png"
 let(Right c)=imageToCanvas i;s=canvasWidth c;q=[3..s-4];(_,g)=foldr f(c,[])$sort[(sqrt$(z x-z s/2)^2+(z y-z s/2)^2,x,y)|x<-q,y<-q]
 print$foldr(d$z s/20)(0,0,0)g

Совет: all idто же самое, что и and.also, вы можете реализовать jс паттернамиj n m|PixelRGBA8 0 255 0 _<-getColor n m v=0<1|0<1=0>1
гордый haskeller

@proudhaskeller: Да, спасибо!
Ними

2

Mathematica - 371 386 - 25 = 361

Более оптимальное решение. Вычисляет ответ намного быстрее, чем мое решение на Python.

i=IntegerPart;c=i/@((NestList[#+.01&,.1,10]~Prepend~1)*100);g[m_]:=Last@@c~Position~#-1&/@(i@Round@Last@#&/@(#*100&/@Riffle[RGBColor/@NestList[#+.01&,{.1,.1,.1},10],Table[Disk[{0,0},n],{n,1,.1,-.1}]]~Graphics~{ImageSize->ImageDimensions[m],PlotRangePadding->None}~ImageMultiply~ChanVeseBinarize[m,"TargetColor"->Green]~ComponentMeasurements~"Max"/.Rule[a_,b_]:>b))//{Total@#,#~Count~0}&

Python с PIL - тривиальное и неоптимальное решение, 961 байт

Это просто попытка продемонстрировать глупый подход к решению проблемы. Для запуска первых двух тестовых случаев требуется ~ 2 минуты, а для запуска третьего в моей системе - ~ 20 минут из-за быстро выстроенного, чрезвычайно ресурсоемкого и отталкивающего алгоритмически сложного кругового детектора. Несмотря на это, он действительно отвечает требованиям, хотя он, безусловно, не оптимально для игры в гольф. Чем больше зеленого на изображении, тем больше времени требуется для его запуска.

from PIL import Image,ImageDraw
a=lambda x,y,w,h:filter(lambda x:0<=x[0]<w and 0<=x[1]<h,[(x-1,y-1),(x,y-1),(x+1,y-    1),(x-1,y),(x,y),(x+1,y),(x-1,y+1),(x,y+1),(x+1,y+1)])
def b(c):
 d=0,255,0;e,f=c.size;g=c.load();h,i=[],[];j=Image.new("RGB",(e,f));k=ImageDraw.Draw(j)
 for l in range(e):
  for m in range(e):
   n=g[l,m][:-1]
   if n==d and(l,m)not in i:
    o=[(l,m)];p=[];q=1
    while q:
     q=0;r=o[:]
     for s in o:
      t=filter(lambda x:g[x[0],x[1]][:-1]==d and(x[0],x[1]) not in r,a(s[0],s[1],e,f))
      if t:
       r+=t
       if len(t)<8:
        p+=[s]
       q=1
     o=r
    h+=[p]
    for u in o:
     i+=[u]
   i+=[(l,m)]
 p=map(lambda x:"#"+str(x)*6,'123456789ab');v=0;k.rectangle((0,0,e,f),fill=p[0])
 for n in p[1:]:
  w=e/20*v;x=e-w;k.ellipse((w,w,x,x),fill=n);v+=1
 y=j.load();z=0
 for l in h:
  v=[]
  for m in l:
   s=y[m[0],m[1]]
   if s not in v:
    v+=[s]
  v=max(v);z+=p.index("#"+''.join(map(lambda x:hex(x)[2:],v)))
 return z

Берет объект изображения PIL и возвращает результат.

Шаги, которые нужно предпринять:

  1. Изолировать зеленые круги (неэффективно)
    • Найдите всех соседей какого-либо пикселя n, если они есть, и добавьте их в круг
    • Определите грубый контур, отфильтровав пиксели с 8 соседями
  2. Нарисуйте целевое представление
    • Создать пустой холст
    • Нарисуйте уникальный цветной фон (легко реализовать промахи)
    • Нарисуйте вложенные эллипсы с уникальными цветами
  3. Определите, в каких зачетных зонах находится каждый круг, определив цвет (ы) цели, которая будет находиться под кругом.
  4. Выберите наивысшую из баллов (если их несколько) и добавьте результат к общему количеству.
  5. Вернуть итог

Ваша функция Python aможет быть записана какa=lambda x,y,w,h:[(X,Y)for X in(x-1,x,x+1)for Y in(y-1,y,y+1)if w>X>-1<Y<h]
ovs
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.