10, 10, 10… Сподіваюсь?


15

Передмова

Коли я стріляв з лука на 900 раундів раніше (10 кінців на 6 стрілках в кінці, і 10 кінців на 3 стрілках в кінці, загалом 90 стрілок і максимальний бал 900), я подумав про це завдання.

У стрільбі з лука (якщо припустити, що ви стріляєте по цільовій обличчі, що постачається FITA [аркуш паперу, в який ви стріляєте]), для кожної стрілки ви можете отримати максимальний бал 10. Цільова грань містить 10 або 11 кілець зменшення діаметра, вкладені всередину один одного. Від внутрішнього кільця назовні вони рахуються від 10 балів до однієї точки (а у випадку з 11 кільцями є вторинне внутрішнє кільце, що рахується як "X", яке набирає значення 10, але використовується у випадках розриву краватки як вище значення). Дотримуйтесь:

Цільовий бал FITA

Звичайно, я маю на увазі оцінку метрики FITA, як видно з наведеної вище ілюстрації. Якщо ви придивитесь уважніше, ви можете спостерігати найпотаємніше кільце - це зів’яла пунктирна лінія, оцінка якої не позначена. Це "X", про який я мав на увазі, але вам не доведеться прислухатися до цього, якщо ви не змагаєтесь за бонус.

Виклик

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

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

Crappy приклад ілюстрації

Роз'яснення

  • Якщо торкатися двох відокремлених кілець, підраховується вища з двох кілець
  • Вам не доведеться автоматично обліковувати пропуски або "x" випадок, якщо тільки не намагаєтеся отримати бонус
  • Ви можете припустити, що жодні зелені кола не перетинаються
  • Ви також можете припустити, що ніяких інших пікселів цього відтінку зеленого немає на зображенні
  • Зображення буде або у форматі PNG, JPEG або PPM (на ваш вибір)
  • Зовнішні бібліотеки обробки зображень дозволені, якщо вони є автором до публікації цього питання
  • Можна припустити, що всі зелені кола на одній цілі матимуть однаковий діаметр
  • Якщо при зйомці (га) для бонусу, що перекривається, ви можете припустити, що принаймні одне коло на зображенні не має іншого перекриття.
  • Стандартні лазівки заборонені

Тестові справи

Наступні два випадки мають набрати 52 (або у випадку бонусів - 52 з 1 'х' та 1 промах):

І цей останній тестовий випадок повинен набрати 25 :

Бонус

  • -25 байт, якщо ви також повернете кількість промахів (поза будь-яким з кілець)
  • -30 байт, якщо ви також повернете кількість Xs (припустимо, що найпотужніший х становить 3/100-ту ширину зображення, а 10 - це 2/100-та ширина зображення. Пропорції 1-9 залишаються незмінними)
  • -35% кількість байтів, якщо ви враховуєте кола, що перекриваються

Це код гольфу, тому виграє найменше байтів. Веселіться!


"30 кінців на 3 стрілках в кінці, в цілому 30 стрілок"? Не повинно це бути 90 стрілок?
DavidC

@DavidCarraher Я зрозумів це право, коли розмістив повідомлення. Виправлено
глобі

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

Скажімо, просто JPEG або PNG для простоти @Doorknob 冰
globby

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

Вихід є трійкою (оцінка, промахи, Xs), наприклад (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
шахраїв

@proudhaskeller: Так, дякую!
німі

2

Математика - 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]
овс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.