एक हेक्सागोनल टाइलिंग पर प्राणियों की गिनती


18

यह चुनौती आपको टाइल गेम पालगो में "जीव" गिनने की होगी ।

प्राणी कोई भी बंद आकृति है जिसे हेक्सागोनल ग्रिड में मिलान रंग के पैलागो टाइल्स द्वारा बनाया जा सकता है।

खेल पैलागो में इस तरह की टाइलें होती हैं:

पलागो की खपरैल

इन टाइलों को 120 , 240 ated घुमाया जा सकता है240 , या बिल्कुल नहीं और एक हेक्सागोनल ग्रिड पर कहीं भी रखा जा सकता है। उदाहरण के लिए, यहां एक (लाल) प्राणी है जिसे 12 टाइलों की आवश्यकता होती है।बारह खपरैल का प्राणी।

चुनौती

इस चुनौती का लक्ष्य एक प्रोग्राम लिखना है जो एक पूर्णांक nको एक इनपुट के रूप में लेता है और nटाइल की आवश्यकता वाले प्राणियों की संख्या (रोटेशन और प्रतिबिंब तक) की गणना करता है । कार्यक्रम को संभाल करने के लिए सक्षम होना चाहिए n=10पर TIO । यह , इसलिए सबसे कम बाइट जीतती है।

उदाहरण डेटा

मूल्यों को निर्माता की वेबसाइट के "क्रिएचर काउंट्स एंड एस्टिमेट्स" अनुभाग में पाए गए डेटा से मेल खाना चाहिए । यानी

 n | output
---+-------
 1 | 0
 2 | 0
 3 | 1 
 4 | 0
 5 | 1
 6 | 1
 7 | 2
 8 | 2
 9 | 9
10 | 13
11 | 37
12 | 81

"कार्यक्रम को n=10TIO पर संभालने में सक्षम होना चाहिए ।" - यदि यह एक निष्पादन गति की आवश्यकता है, तो कोड-गोल्फ के बजाय कोड-चुनौती का उपयोग करें , बाद में एक शुद्ध बाइट अनुकूलन कार्य का जिक्र है।
जोनाथन फ्रेच

10
यहां चर्चा के आधार पर , ऐसा लगता है कि कोड-गोल्फ प्रश्न में निष्पादन गति की आवश्यकता होना ठीक है , जब तक स्कोरिंग बाइट्स की संख्या है।
पीटर कैगी

2
+1 सर्पिल अनुक्रम की तरह , यह चुनौती समझना आसान है और हल करने के लिए वास्तव में दिलचस्प है ... लेकिन इसके लिए काफी कोड की आवश्यकता है। : पी
अरनुलद

1
तो .... हम सिर्फ एक इनपुट ले रहे हैं और 1 से 10 के बीच n के लिए ऊपर की सूची से आउटपुट वापस कर रहे हैं? क्या मैं सिर्फ लुकअप टेबल का उपयोग कर सकता हूं?
ब्रैड सी पी

6
@BradC यह एक डिफ़ॉल्ट कमियां है । ओपी ने सिर्फ इतना कहा कि समाधान TIO पर तक को संभालने में सक्षम होना चाहिए । n=10
अरनुलद

जवाबों:


5

जावास्क्रिप्ट (Node.js) , 480 417 बाइट्स

-63 बाइट्स @Arnauld की बदौलत। वाह।

n=>(E=(x,y,d,k,h)=>V[k=[x+=1-(d%=3),y+=~d%3+1,d]]?0:(V[k]=1,h=H.find(h=>h[0]==x&h[1]==y))?(d^(t=2-h[2])?E(x,y,t)||E(x,y,h[2]*2):E(x,y,t+2)):[x,y,0],I=c=>c.map(([x,y,t])=>[x-g(0),y-g(1),t],g=p=>Math.min(...c.map(h=>h[p]))).sort(),S=e=>(V={},e=E(0,0,0))?(--n&&H.pop(H.push(e),S(),S(e[2]=1),S(e[2]=2)),++n):n-1||E[I(c=H)]||[0,0,0,++N,0,0].map(r=>E[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1))(H=[[N=0,0,1]])&&N

इसे ऑनलाइन आज़माएं!

सबसे पहले, अरनुलद को पछतावा हुआ जिनके जवाब से मुझे गहरी खुदाई करने की प्रेरणा मिली। मैंने अपने एल्गोरिदम के साथ मूल होने की बहुत कोशिश की है, हालांकि मैंने जानबूझकर अपने कुछ कोड को बदलकर Arnauld के समान चर का उपयोग किया है ताकि कोड की तुलना में अधिक आसानी से हो सके।

खाली हेक्स की खोज करना

प्राणियों की खोज है:

  • 0,0 पर टाइल 1 के साथ टाइल की प्रारंभिक सूची
  • रिकर्सिवली:
    • एक खाली हेक्स की खोज करें जो प्राणी को पूरा करने के लिए आवश्यक है
    • यदि खाली हेक्स पाया गया
      • खाली हेक्स और पुनरावृत्ति करने के लिए प्रत्येक प्रकार की टाइल 0,1,2 जोड़ें
    • यदि खाली हेक्स नहीं मिला
      • यदि प्राणी सही आकार का है और पहले से ही चिड़ियाघर में नहीं है
        • एक के बाद एक अलग-अलग जीवों की बढ़ती संख्या
        • प्राणी के सभी घुमावों और प्रतिबिंबों को चिड़ियाघर में जोड़ें

खाली हेक्स की खोज ने एक दिलचस्प समरूपता का खुलासा किया। अर्नुलद ने पाया कि छह दिशाओं में से एक को अनदेखा किया जा सकता है, लेकिन वास्तव में छह में से तीन को अनदेखा किया जा सकता है!

यहां अर्नुल्ड की मूल दिशा और टाइल कुंजी है:

अरनुल्द की दिशा और टाइल की

कल्पना करें कि हम ब्लू डॉट पर टाइप 1 के टाइल ए पर शुरू करते हैं। ऐसा लगता है कि हमें d = 0 और d = 5 में पुनरावृत्ति करनी है। हालाँकि, जो भी टाइल d = 0 में रखी गई है, वह निश्चित रूप से d = 4 में एक निकास होगी, जो d = 5 में बाहर निकलने वाली टाइल A के समान ही हेक्स का दौरा करेगी। यही अर्नुल्ड की खोज है, और यही मुझे सोचने लगा है।

नोटिस जो:

  • प्रत्येक टाइल जिसमें d = 0 का निकास होता है, d = 5 का निकास होता है
  • प्रत्येक टाइल जिसमें d = 2 का निकास होता है, d = 1 का निकास होता है
  • प्रत्येक टाइल जिसमें d = 4 का निकास होता है, d = 3 का निकास होता है

  • प्रत्येक टाइल जो d = 0 से दर्ज की जा सकती है, d = 4 में एक निकास है

  • प्रत्येक टाइल जो d = 2 से दर्ज की जा सकती है, d = 0 में एक निकास है
  • प्रत्येक टाइल जो d = 4 से दर्ज की जा सकती है, d = 2 में एक निकास है

इसका मतलब है कि हमें केवल 0,2,4 दिशाओं पर विचार करने की आवश्यकता है। 1,3,5 दिशाओं में किसी भी निकास को नजरअंदाज किया जा सकता है क्योंकि 1,3,5 दिशाओं में पहुंचता है इसके बजाय 0,2 या 4 दिशाओं का उपयोग करके आसन्न हेक्स से पहुंचा जा सकता है।

कितना मजेदार था वो!?

पुनः निर्देशित दिशाएँ

इसलिए मैं दिशाओं और टाइलों को इस तरह रिले करता हूं (अरनुल्ड की छवि संपादित की गई):

सरलीकृत दिशा

अब हमारे पास टाइलों, प्रविष्टियों और निकास के बीच निम्नलिखित संबंध हैं:

    |  t=0  |  t=1  |  t=2
----+-------+-------+-------
d=0 |  0,2  |  1,2  |    2
d=1 |  0,2  |    0  |  0,1
d=2 |    1  |  1,2  |  0,1

तो बाहर निकलें हैं: d + t == 2? (4-टी)% 3: 2-टी और 2 * टी% 3

हेक्सागोनल रोटेशन और प्रतिबिंब

रोटेशन और प्रतिबिंब के लिए, मैंने एक्स, वाई, जेड क्यूब निर्देशांक के बजाय एक्स, वाई हेक्सागोनल अक्षीय निर्देशांक की कोशिश करने का फैसला किया ।

-1,2   0,2   1,2   2,2
    0,1   1,1   2,1
 0,0   1,0   2,0   3,0

इस प्रणाली में, रोटेशन और परावर्तन मेरी अपेक्षा से अधिक सरल थे:

120 Rotation:   x=-x-y   y=x   t=(t+1)%3
Reflection:     x=-x-y   y=y   t=(t*2)%3

मेरे द्वारा किए गए सभी संयोजनों को प्राप्त करने के लिए: सड़ांध, सड़ांध, सड़ांध, प्रतिबिंबित, सड़ांध, सड़ांध

कोड (मूल 480 बाइट)

f=n=>(
    // H:list of filled hexes [x,y,tile] during search for a complete creature
    // N:number of distinct creatures of size n
    // B:record of all orientations of all creatures already found
    H=[[0,0,1]],N=0,B={},

// E: find an empty hex required to complete creature starting in direction d from x,y
    E=(x,y,d,k,h)=>(
        x+=1-d,
        y+=1-(d+1)%3,
        // V: list of visited hexes during this search in E
        V[k=[x,y,d]] ? 
            0
        : (V[k]=1, h=H.find(h=>h[0]==x&&h[1]==y)) ? 
            // this hex is filled, so continue search in 1 or 2 directions
            (d==2-h[2] ? E(x,y,(4-h[2])%3) : (E(x,y,2-h[2]) || E(x,y,h[2]*2%3))) 
        : [x,y,0] // return the empty hex 
    ),

    // I: construct unique identifier for creature c by moving it so x>=0 and y>=0
    I=c=>(
        M=[0,1].map(p=>Math.min(...c.map(h=>h[p]))),
        c.map(([x,y,t])=>[x-M[0],y-M[1],t]).sort()
    ),

    // A: add complete creature c to B
    A=c=>{
        n==1&&!B[I(c)]&&(
            // creature is correct size and is not already in B
            N++,
            [0,0,0,1,0,0].map(
                // Add all rotations and reflections of creature into B
                // '0' marks a rotation, '1' marks a (vertical) reflection
                // rotation:   x=-x-y   y=x   t=(t+1)%3
                // reflection: x=-x-y   y=y   t=(t*2)%3
                r=>B[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1)          
        )
    },

    // S: recursively search for complete creatures starting with hexes H
    S=e=>{
        V={};
        (e=E(0,0,0)) ?
            // e is a required empty hex, so try filling it with tiles 0,1,2
            (--n && (H.push(e),S(),S(e[2]=1),S(e[2]=2),H.pop()), ++n)
        : A(H) // creature is complete, so add it to B
    },

    S(),
    N
)

कोड (अरनौल 417 बाइट)

अरनुल्द ने कृपया 63 बाइट की बचत प्रस्तुत की, जिसमें ट्रिक्स का इस्तेमाल किया गया जिससे मुझे अपना सिर लपेटने में काफी समय लगा। चूंकि इसमें कई दिलचस्प संपादन हैं, इसलिए मुझे लगा कि मैं उसका कोड नीचे रख दूंगा (मैंने अपनी टिप्पणियाँ जोड़ दी हैं) ताकि यह मेरे संस्करण के साथ विपरीत हो सके।

f=n=>(
    // E:find an empty hex required to complete creature starting in direction d from x,y
    E=(x,y,d,k,h)=>
      V[k=[x+=1-(d%=3),y+=~d%3+1,d]] ?
        0
      :(V[k]=1,h=H.find(h=>h[0]==x&h[1]==y)) ?
        (d^(t=2-h[2]) ? E(x,y,t) || E(x,y,h[2]*2) : E(x,y,t+2))
      :[x,y,0],

    // I: construct unique identifier for creature c by moving it so x>=0 and y>=0
    I=c=>c.map(([x,y,t])=>[x-g(0),y-g(1),t],g=p=>Math.min(...c.map(h=>h[p]))).sort(),

    // S: recursively search for complete creatures starting with hexes H
    S=e=>
      (V={},e=E(0,0,0)) ?
        (--n&&H.pop(H.push(e),S(),S(e[2]=1),S(e[2]=2)),++n)
      :n-1
        ||E[I(c=H)] 
        // creature is the correct size and has not been seen before
        // so record all rotations and reflections of creature in E[]
        ||[0,0,0,++N,0,0].map(r=>E[I(c=c.map(([x,y,t])=>[-x-y,r?y:x,(r?t*2:t+1)%3]))]=1)
)
// This wonderfully confusing syntax initializes globals and calls S()
(H=[[N=0,0,1]]) && N

दिशाओं पर अच्छी जानकारी! और मुझे लगता है कि यह मेरे उत्तर के आकार से नीचे हो सकता है।
अरनौलड


@Arnauld यह कमाल है! अब मेरे सामने एक बड़ा काम करने का दिन है, लेकिन कल इसकी जांच करने के लिए तत्पर हूं। धन्यवाद।
जॉन रीस

20

जावास्क्रिप्ट (Node.js) ,  578 ... 433  431 बाइट्स

f=(n,T=[B=[N=0,0,0,1,1]])=>!n||T.some(([x,y,q,m])=>B.some((p,d)=>m>>d&1&&((p=x+~-s[d],q=y+~-s[d+2],t=T.find(([X,Y])=>X==p&Y==q))?(q=t[3])&(p=D[d*3+t[4]])^p?t[f(n,T,t[3]|=p),3]=q:0:[0,1,2].map(t=>f(n-1,[...T,[p,q,-p-q,D[d*3+t],t]])))),s="2100122",D=Buffer("160).(9!'8 &$<%"))|n>1||[0,1,2,1,2,0].some((_,d,A)=>B[k=T.map(a=>[(h=n=>Math.min(...T.map(R=a=>a[A[(d+n)%6]]))-R(a))(0),h(3),(x=(a[4]+d*2)%3,d>2)*x?3-x:x]).sort()])?N:B[k]=++N

n=1n=13 )

कैसे?

दिशा और टाइल

हम 6-दिशा कम्पास और टाइल्स के लिए निम्नलिखित कोड का उपयोग करते हैं:

दिशा और टाइल

हम मानते हैं कि जीव नीला है।

सम्बन्ध

जब हम किसी दिए गए दिशा में एक टाइल डालते हैं, तो हमें यह जानने के लिए एक तालिका की आवश्यकता होती है कि प्राणी के किन हिस्सों को अन्य टाइलों से जोड़ा जाना चाहिए:

     |  T=0  |  T=1  |  T=2
-----+-------+-------+-------
 d=0 | 0,4,5 | 1,2,4 |   4
 d=1 | 0,3,5 | 1,2,3 |   3
 d=2 | 0,3,4 |   0   | 0,1,2
 d=3 | 3,4,5 |   5   | 1,2,5
 d=4 |   2   | 2,3,4 | 0,2,5
 d=5 |   1   | 1,3,4 | 0,1,5

उदाहरण:

यदि हम टाइप की टाइल डालते हैं15134

सम्बन्ध

5

     |  T=0  |  T=1  |  T=2
-----+-------+-------+-------
 d=0 |  0,4  | 1,2,4 |   4
 d=1 |  0,3  | 1,2,3 |   3
 d=2 | 0,3,4 |   0   | 0,1,2
 d=3 |  3,4  |   -   |  1,2
 d=4 |   2   | 2,3,4 |  0,2

+32

     |  T=0  |  T=1  |  T=2              |  T=0  |  T=1  |  T=2
-----+-------+-------+-------       -----+-------+-------+-------
 d=0 |   17  |   22  |   16          d=0 |  "1"  |  "6"  |  "0"
 d=1 |    9  |   14  |    8          d=1 |  ")"  |  "."  |  "("
 d=2 |   25  |    1  |    7    -->   d=2 |  "9"  |  "!"  |  "'"
 d=3 |   24  |    0  |    6          d=3 |  "8"  |  " "  |  "&"
 d=4 |    4  |   28  |    5          d=4 |  "$"  |  "<"  |  "%"

एक बार चपटा, यह देता है:

D = Buffer("160).(9!'8 &$<%")

निर्देशांक

एक्स+y+z=0

घन निर्देशांक

क्रेडिट: www.redblobgames.com

एल्गोरिथ्म के अंतिम चरण में घुमाव और प्रतिबिंब को संसाधित करना आसान होगा।

टाइल एन्कोडिंग

टाइल्स एक सूची में संग्रहीत की जाती हैं, जिसमें कोई विशिष्ट क्रम नहीं होता है। इसका मतलब है कि हमें कुछ गतिशील 2D आवंटन के बारे में चिंता करने की ज़रूरत नहीं है और हम आसानी से मौजूदा टाइल्स पर पुनरावृति कर सकते हैं। नकारात्मक पक्ष यह है कि, विशिष्ट निर्देश दिए गए हैं, हमें इसकी आवश्यकता हैfind() सूची में संबंधित टाइल की ।

प्रत्येक टाइल को रूप में संग्रहीत किया जाता है(एक्स,y,z,,टी)

  • (एक्स,y,z)
  • टी012)

कलन विधि

हम एक प्रकार की एकल टाइल से शुरू करते हैं 1 पर (0,0,0), दिशा में एक आवश्यक कनेक्शन के साथ 0:

प्रारंभिक टाइल

इसलिए, इस टाइल को एन्कोड किया गया है [0,0,0,1,1]

प्रत्येक पुनरावृत्ति पर, हम निम्न की तलाश करते हैं:

  • गुम कनेक्शन वाली टाइलें: इस मामले में, हम क्रमिक रूप से प्रत्येक प्रकार के टाइल के साथ कनेक्शन को पूरा करने का प्रयास करते हैं।

  • टाइलें जो पहले से ही जुड़ी हुई हैं, लेकिन जिनके लिए नए कनेक्शन जोड़े जाने की आवश्यकता है, क्योंकि वे एक अलग दिशा में पहुँच चुके हैं: इस मामले में, हम दिशा मास्क को अपडेट करते हैं (एक बिटवाइज़ OR के साथ) और एक नई पुनरावृत्ति के लिए मजबूर करते हैं।

यदि सभी कनेक्शन वैध हैं और हम टाइलों की अनुरोधित संख्या तक पहुँच चुके हैं, तो हमें अभी भी यह जाँचने की आवश्यकता है कि क्या यह एक नया प्राणी है या किसी मौजूदा का संशोधित संस्करण है:

  1. हम निम्नलिखित परिवर्तन लागू करते हैं:

    • हम 3 संभावित घुमावों को प्रतिस्थापित करके प्रदर्शन करते हैं (एक्स,y) साथ में (एक्स,y) (कोई रोटेशन नहीं), (y,z) (120 °) या है (z,एक्स) (240 °), और तदनुसार टाइल्स के प्रकार को अद्यतन करना।

    • हम 3 समान प्रतिबिंबों को प्रतिस्थापित करके प्रदर्शन करते हैं (एक्स,y) साथ में (y,एक्स), (z,y) या (एक्स,z), और तदनुसार टाइल्स के प्रकार को अद्यतन करना।

  2. प्रत्येक परिवर्तन के लिए, हम सभी टाइलों का अनुवाद करते हैं ताकि नीचे-दाएं कोने हमेशा स्थित हों (0,0)। (निर्देशांक के संकेत प्रक्रिया में उल्टे हैं, जो तकनीकी रूप से एक और प्रतिबिंब की ओर जाता है, लेकिन यह हानिरहित है।)

  3. हम टाइल्स को उनके निर्देशांक और प्रकार के अनुसार क्रमबद्ध करते हैं। (इस प्रकार को लेक्सोग्राफिक क्रम में संसाधित किया जाता है, जो ठीक है।)

  4. हम अंत में परिणामी सूची को एक कुंजी स्ट्रिंग पर ले जाते हैं, जिसकी तुलना अन्य कुंजी के साथ की जा सकती है।

  5. जैसे ही किसी ज्ञात कुंजी का मिलान किया जाता है, हम निरस्त कर देते हैं, या नई कुंजी संग्रहीत करते हैं और अंतिम परिणाम को बढ़ाते हैं यदि कोई भी परिवर्तन ज्ञात कुंजी की ओर नहीं जाता है।

टिप्पणी की गई

f = (n, T = [B = [N = 0, 0, 0, 1, 1]]) =>
  // abort if n = 0
  !n ||
  // for each tile in T
  T.some(([x, y, q, m]) =>
    // for d = 0 to d = 4
    B.some((p, d) =>
      // if this tile requires a connection in this direction
      m >> d & 1 && (
        // look for a connected tile t at the corresponding position (p, q)
        (
          p = x + ~-s[d],
          q = y + ~-s[d + 2],
          t = T.find(([X, Y]) => X == p & Y == q)
        ) ?
          // if t exists, make sure that its direction mask is up-to-date
          (q = t[3]) & (p = D[d * 3 + t[4]]) ^ p ?
            // if it's not, update it and force a new iteration
            t[f(n, T, t[3] |= p), 3] = q
          :
            0
        :
          // if t does not exist, try each type of tile at this position
          [0, 1, 2].map(t => f(n - 1, [...T, [p, q, -p - q, D[d * 3 + t], t]]))
      )
    ),
    // s is used to apply (dx, dy)
    s = "2100122",
    // D holds the direction masks for the connections
    D = Buffer("160).(9!'8 &$<%")
  ) |
  // stop here if the above some() was truthy or we have more tiles to add
  n > 1 ||
  // otherwise, apply the transformations
  [0, 1, 2, 1, 2, 0].some((_, d, A) =>
    B[
      // compute the key k
      k =
        // by generating the updated tuples [x, y, type] and sorting them
        T.map(a =>
          [
            // transform the 1st coordinate
            (h = n => Math.min(...T.map(R = a => a[A[(d + n) % 6]])) - R(a))(0),
            // transform the 2nd coordinate
            h(3),
            // update the type
            (x = (a[4] + d * 2) % 3, d > 2) * x ? 3 - x : x
          ]
        ).sort()
    ]
  ) ?
    // if the key was found, just return N
    N
  :
    // if this is a new creature, store its key and increment N
    B[k] = ++N

इस उत्तर को प्यार करो। मुझे मिल गया यह सप्ताहांत पर एक शॉट देने के लिए सभी निकाल दिया!
जॉन रीस

मैं बस एक जवाब पोस्ट करने वाला हूं, मुझे आशा है कि आपको दिलचस्प लगेगा। क्या मेरी व्याख्या में मदद करने के लिए आपके चित्रों में से एक का उपयोग करना मेरे लिए ठीक होगा? मैं आपको इसका श्रेय दूंगा।
जॉन रीस

@ जॉनीआरस ज़रूर, कोई बात नहीं।
Arnauld
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.