একটি বরং নন্টি কনড্রাম


23

গাঁটের কাঠামোর উপর ভিত্তি করে গিঁটের 2-ডি চিত্র আঁকার জন্য একটি প্রোগ্রাম লিখুন। গিঁটটি যা শোনাচ্ছে ঠিক তেমনই: বাঁধা দড়িটির একটি লুপ। গণিতে, একটি গিঁট চিত্রটি দেখায় যেখানে গিঁটটি তৈরি করার জন্য একটি টুকরো টুকরো নিজের উপরে বা নীচে পেরিয়ে যায়। কয়েকটি গিঁটের চিত্র নীচে দেখানো হয়েছে:

এখানে চিত্র বর্ণনা লিখুন

লাইনে একটি ব্রেক রয়েছে যেখানে দড়িটি নিজের উপর দিয়ে গেছে।

ইনপুট: গিঁট বর্ণনকারী ইনপুটটি পূর্ণসংখ্যার একটি অ্যারে। একটি গিঁট যেখানে দড়ি নিজের উপর n বার অতিক্রম করে তাকে এন ইন্টিজারের অ্যারে হিসাবে উপস্থাপন করা যেতে পারে , প্রতিটি মানের মধ্যে [0, n-1]। আসুন এই অ্যারে কে কল করুন ।

অ্যারে একটি গিঁট বর্ণনাকরন করতে, n-1 এর মাধ্যমে 0 টি বিভাগের প্রতিটি নম্বর করুন। সেগমেন্ট 0 এর সাথে বিভাগ 1 টিতে নেতৃত্ব দেওয়া উচিত, যা বিভাগ 2-এর দিকে পরিচালিত হওয়া উচিত, যা খণ্ড 3-এ নিয়ে যাবে এবং সেগমেন্ট এন -1 টি পিছনে ফিরে আসা এবং সেগমেন্ট 0-এ পৌঁছানো পর্যন্ত একটি অংশটি শেষ হয় যখন দড়িটির অন্য একটি বিভাগটি তার উপর দিয়ে যায় ( চিত্রের রেখায় বিরতি দ্বারা প্রতিনিধিত্ব করা হয়েছে)। আসুন সহজ গিঁটটি দেওয়া যাক - ট্র্যাফয়েল নট। আমরা সেগমেন্টগুলি সংখ্যাযুক্ত করার পরে, বিভাগটি 0 শেষ হবে যখন বিভাগটি 2 এর উপর দিয়ে যাবে; বিভাগটি 1 শেষ হয় যখন বিভাগ 0 এর উপর দিয়ে গেছে; এবং বিভাগ 2 শেষ হবে যখন বিভাগ 1 তার উপর দিয়ে যাবে। সুতরাং, গিঁটকে বর্ণনা করে এমন অ্যারে হ'ল [2, 0, 1]। সাধারণভাবে, সেগমেন্ট এক্স শুরু হয় যেখানে বিভাগ -1-মোড এন ছেড়ে গেছে এবং যেখানে সেগমেন্ট কে [এক্স] এর উপর দিয়ে গেছে সেখানে শেষ হবে।

নীচের চিত্রটি নট চিত্রগুলি দেখায়, লেবেলযুক্ত বিভাগগুলি এবং নটকে বর্ণনা করে এমন সম্পর্কিত অ্যারেগুলি সহ।

এখানে চিত্র বর্ণনা লিখুন

শীর্ষ তিনটি চিত্র সঠিক নট, যখন নীচের তিনটি রশি এর লুপ যা তাদের নিজের উপর দিয়ে গেছে তবে আসলে গিঁটে নেই (তবে এখনও এর সাথে সংশ্লিষ্ট কোড রয়েছে)।

আপনার কাজটি এমন একটি ফাংশন লিখুন যা পূর্ণসংখ্যার কে এর অ্যারে নেয় (আপনি এটিকে কিছু আলাদা বলতে পারেন) যা কোনও গিঁট (বা দড়িটির লুপ যা আসলে গিঁটে না) বর্ণনা করে এবং যা উপরের বর্ণনায় বর্ণিত অনুরূপ নট ডায়াগ্রাম তৈরি করে উদাহরণ। যদি আপনি পারেন তবে আপনার কোডের একটি বর্ণহীন সংস্করণ বা ব্যাখ্যা সরবরাহ করুন এবং আপনার কোডের নমুনা আউটপুট সরবরাহ করুন। একই নট প্রায়শই একাধিক বিভিন্ন উপায়ে প্রতিনিধিত্ব করা যেতে পারে, তবে যদি নট ডায়াগ্রামটি আপনার ফাংশন আউটপুট সন্তুষ্ট করে তবে এর সম্ভাব্য উপস্থাপনাগুলির একটি হিসাবে ইনপুট থাকে, আপনার সমাধানটি বৈধ।

এটি কোড-গল্ফ, তাই বাইট জেতে সংক্ষিপ্ততম কোড। দড়ির প্রতিনিধিত্বকারী রেখার দৈর্ঘ্য 1 পিক্সেল হতে পারে, তবে নীচে এবং ওভারস্রোসিংগুলি অবশ্যই স্পষ্টভাবে পৃথক করতে হবে (দড়ির বিরতির আকার দুটি পাশের কমপক্ষে একটি পিক্সেলের দ্বারা দড়িটির বেধের চেয়ে বেশি হওয়া উচিত) ।

আমি উত্তরগুলিকে উজ্জীবিত করব যা অন্তর্নির্মিত নট তত্ত্বের ক্ষমতার উপর নির্ভর করে, তবে শেষ পর্যন্ত যেটি নির্বাচিত হয় সে অন্তর্নির্মিত নট তত্ত্বের ক্ষমতাগুলিতে নির্ভর করতে পারে না।

আমার স্বীকৃতি সম্পর্কে আমি যা জানি তা: আমি বিশ্বাস করি যে এখানে মানগুলির ক্রম রয়েছে যা কোনও গিঁট বা অচেনা মেলেনি বলে মনে হয়। উদাহরণস্বরূপ, ক্রম [2, 3, 4, 0, 1] আঁকানো অসম্ভব বলে মনে হচ্ছে।

এর বাইরে, ধরুন যে আপনি একটি ক্রসিং নিয়ে এসেছেন এবং সেই ক্রসিং থেকে শুরু করে, দড়িটির পথটি এক দিকে অনুসরণ করুন এবং প্রতিটি লেবেলযুক্ত ক্রসিং লেবেল করুন যা আপনি সফলভাবে বৃহত্তর অবিচ্ছেদ্য মানগুলি নিয়ে এসেছেন। বিকল্প নটগুলির জন্য, আমার স্বরলিপিটি এ জাতীয় লেবেলিংয়ে রূপান্তর করার জন্য একটি সহজ অ্যালগরিদম রয়েছে এবং গিঁটকে পরিবর্তিত করার জন্য গিঁটের কোডে এই লেবেলটিকে রূপান্তর করা নিতান্ত পরিবর্তনযোগ্য:

template<size_t n> array<int, 2*n> LabelAlternatingKnot(array<int, n> end_at)
{
    array<int, n> end_of;
    for(int i=0;i<n;++i) end_of[end_at[i]] = i;
    array<int, 2*n> p;
    for(int& i : p) i = -1;
    int unique = 0;
    for(int i=0;i<n;i++)
    {
        if(p[2*i] < 0)
        {
            p[2*i] = unique;
            p[2*end_of[i] + 1] = unique;
            ++unique; 
        }
        if(p[2*i+1] < 0)
        {
            p[2*i+1] = unique;
            p[2*end_at[i]] = unique;
            ++unique;
        }
    }
    return p;
}
template<size_t n> auto GetGaussCode(array<int, n> end_at)
{
    auto crossings = LabelAlternatingKnot(end_at);
    for(int& i : crossings) ++i;
    for(int i=1;i<2*n;i+=2) crossings[i] = -crossings[i];
    return crossings;
}

4
এটি করার জন্য আপনার সম্ভবত বিল্টিনগুলি নিষিদ্ধ করা উচিত। (এই মুহুর্তে, যদি

7
@ ais523 এখন আমি KnotDataম্যাথমেটিকায় ব্যবহার করতে পারি না ...: '(
জংহওয়ান মিন

1
নট ক্রসিং ডায়াগ্রামের জন্য আপনি যে স্বীকৃতিটি ব্যবহার করছেন তা সম্পর্কে আমি আগ্রহী। এটির কি একটি নাম আছে? দুটি অ-সমমানের গিঁটের জন্য একই অ্যারে থাকা কি সম্ভব?
xnor

2
@ আইস ৫৩৩: গণিতের পুরোপুরি বিল্টিন রয়েছে Knot! ব্যবহারের উদাহরণ: << Units`; Convert[Knot, Mile/Hour]ফলন 1.1507794480235425 Mile/Hour। (আমি মনে করি এটি সত্য বা মিথ্যা নির্বিশেষে এটি মজাদার; তবে এটি সত্যই সত্য))
গ্রেগ মার্টিন

1
[0], [0,1], [0,1,2], [1,0] এবং অন্যান্য বিভিন্ন অ্যারে সমস্ত "নট" উত্পাদন করে যা আনকোটের সমতুল্য, তবে সরল লুপ আউটপুট করাতে ভুল হবে এই ক্ষেত্রে যে কোনও। স্বরলিপি [0] এর খুব নির্দিষ্ট অর্থ দড়িটির একটি লুপ যা নিজেকে একবারে একেবারে ছেদ করে এবং স্ক্রিনে আঁকানো কোনও চিত্র ইনপুট স্বরলিপি সন্তুষ্ট করে কিনা তা বলা খুব সহজ।
জে আন্তোনিও পেরেজ

উত্তর:


22

জিএনইউ প্রোলগ, 622 634 কোড পৃষ্ঠা 850 এ 668 বাইট

হালনাগাদ : প্রোগ্রামটির পূর্ববর্তী সংস্করণটি মাঝে মধ্যে ক্রসিংগুলি এতোটাই শক্ত করে তোলে যে তারা যথাযথভাবে রেন্ডার করতে পারে না, যা অনুমানটিকে লঙ্ঘন করে। আমি এটি রোধ করতে কিছু অতিরিক্ত কোড যুক্ত করেছি।

হালনাগাদ : স্পষ্টতই পিপিসিগির নিয়মগুলির জন্য প্রোগ্রামটি প্রস্থান করতে এবং শুরুতে যেমন ছিল ঠিক তেমন অবস্থা পুনরুদ্ধার করতে অতিরিক্ত কোডের প্রয়োজন হয়। এটি প্রোগ্রামটিকে কিছুটা দীর্ঘায়িত করে এবং এতে কোনও অ্যালগরিদমিক আগ্রহ যুক্ত করে না, তবে নিয়ম মেনে চলার স্বার্থে, আমি এটিকে পরিবর্তন করেছি।

গল্ফ প্রোগ্রাম

জিএনইউ প্রোলোগ ব্যবহার করা হচ্ছে কারণ এতে একটি সীমাবদ্ধ দ্রাবক বাক্য গঠন যা পোর্টেবল প্রোলোগের পাটিগণিত সিনট্যাক্সের চেয়ে কিছুটা ছোট, কয়েকটি বাইট সংরক্ষণ করে।

y(A,G):-A=1;A= -1;A=G;A is-G.
z(A/B,B,G):-y(A,G),y(B,G),A=\= -B.
v(D,E,G):-E=1,member(_-_,D),p(D);F#=E-1,nth(F,D,M),(M=[_];M=L-S/R,z(L,O,G),J is F+O,nth(J,D,I/U-T/Q),(I=O,Q#=R-1,S=T;K is J+O,R=0,n(S-T-V),y(U,G),U\=O,U=\= -O,I=U,nth(K,D,O/_-V/_))),v(D,F,G).
i([H|K],S):-K=[]->assertz(n(S-H-0));T#=S+1,assertz(n(S-H-T)),i(K,T).
t([],1,_):-!.
t(D,R,G):-S#=R-1,t(E,S,G),H#=G-1,length(F,H),append(F,[[x]|E],D).
s(1,2).
s(-1,1).
s(S,T):-S>1->T=3;T=0.
r(I/O-_,C):-s(I,J),s(O,P),N#=J*4+P+1,nth(N,"│┐┌?└─?┌┘?─┐?┘└│",C).
r([X],C):-X\=y->C=10;C=32.
p([]).
p([H|T]):-r(H,C),put_code(C),!,p(T).
g(4).
g(G):-g(H),G#=H+1.
m(K):-i(K,0),g(G),t(D,G,G),length(D,L),v(D,L,G),abolish(n/1).

অ্যালগরিদম

এটি সেই সমস্যাগুলির মধ্যে একটি যেখানে এটি কীভাবে শুরু করা শক্ত know প্রদত্ত স্বরলিপি থেকে কীভাবে গিঁটের আকৃতিটি কার্যকর করা যায় তা স্পষ্ট নয়, কারণ এটি আপনাকে জানায় না যে আপনি কোনও নির্দিষ্ট অবস্থানে বাম বা ডানদিকে রেখাটি বাঁকতে চেয়েছিলেন (এবং যেমন, স্বরলিপি অস্পষ্ট হতে পারে)। আমার সমাধানটি ছিল কার্যকরভাবে, পুরানো গল্ফিং স্ট্যান্ডবাই ব্যবহার করার জন্য: একটি অবিশ্বাস্যভাবে অদক্ষ প্রোগ্রাম লিখুন যা সমস্ত সম্ভাব্য আউটপুট উত্পন্ন করে এবং তারপরে তারা ইনপুটটির সাথে মেলে কিনা তা দেখুন। (এখানে ব্যবহৃত অ্যালগরিদম খানিকটা বেশি দক্ষ, কারণ প্রোলোগ মাঝেমধ্যে শেষ প্রান্তটি ফেলে দিতে পারে, তবে কম্পিউটেশনাল জটিলতার উন্নতি করার জন্য এটিতে পর্যাপ্ত তথ্য নেই))

আউটপুটটি টার্মিনাল আর্টের মাধ্যমে। জিএনইউ প্রোলজ মনে হয় যে একটি একক বাইট চরিত্রের সেটটি ASCII এর সাথে সামঞ্জস্যপূর্ণ, তবে কোনটি ব্যবহার করা হবে তা যত্নশীল করে না (কারণ এটি উচ্চ বিট সেটটিকে অস্বচ্ছ হিসাবে অক্ষরের সাথে আচরণ করে)। ফলস্বরূপ, আমি আইবিএম 850 ব্যবহার করেছি, যা বহুলভাবে সমর্থিত এবং আমাদের প্রয়োজনীয় লাইন অঙ্কনের অক্ষর রয়েছে।

আউটপুট

প্রোগ্রামটি সমস্ত গিঁট চিত্রগুলি তাদের সীমানা বাক্সের আকারের ক্রম অনুসারে অনুসন্ধান করে, যখন এটি প্রথমটি খুঁজে পায় তখন উপস্থিত হয়। আউটপুটটি দেখতে কেমন লাগে তা এখানে m([0]).:

 ┌┐
┌│┘
└┘ 

এটি আমার কম্পিউটারে চালাতে 290.528 সেকেন্ড সময় নিয়েছে; প্রোগ্রামটি খুব দক্ষ নয়। আমি এটি দুই ঘন্টা চালিয়ে রেখেছি এবং এটি দিয়ে m([0,1])শেষ করেছি:

┌┐┌┐
└─│┘
 └┘ 

মন্তব্য সহ দর্শনীয় সংস্করণ

স্ট্যাক এক্সচেঞ্জের সিনট্যাক্স হাইলাইটারটিতে প্রোলোগের জন্য ভুল মন্তব্য প্রতীক রয়েছে বলে মনে হয়, সুতরাং %মন্তব্যের পরিবর্তে (যা প্রকোলোগ আসলে ব্যবহার করেন), এই ব্যাখ্যা % #মন্তব্যগুলি ব্যবহার করে (যা অবশ্যই শুরু করার কারণে সমতুল্য %, তবে সঠিকভাবে হাইলাইট করুন)।

% # Representation of the drawing is: a list of:
% #     indelta/outdelta-segment/distance  (on path)
% # and [x] or [_]                         (off path; [x] for border).
% # A drawing is valid, and describes a knot, if the following apply
% # (where: d[X] is the Xth element of the drawing,
% #         k[S] is the Sth element of the input,
% #         n[S] is S + 1 modulo the number of sections):
% # d[X]=_/O-S-R, R>1 implies d[X+O]=O/_-S-(R-1)
% # d[X]=_/O-S-0 implies d[X+O]=_/_-k[S]-_
% #                  and d[X+O*2]=O/_-n[S]-_
% # all outdeltas are valid deltas (±1 row/column)

% # not technically necessary, but makes it possible to compile the
% # code (and thus makes the program faster to test):
:- dynamic([n/1]).

% # legal delta combinations:
y(A,G):-A=1;A= -1;              % # legal deltas are 1, -1,
        A=G;A is-G.             % # grid size, minus grid size
z(A/B,B,G):-y(A,G),y(B,G),      % # delta components are valid
            A=\= -B.            % # doesn't U-turn
% # z returns the outdelta for convenience (= byte savings) later on

% # We use v (verify) to verify the first E-1 elements of a drawing D.
% # nth is 1-indexed, so we recurse from length(D)+1 down to 2, with
% # 1 being the trivial base case. After verifying, the grid is printed.
% # This version of the program causes v to exit with success after
% # printing one grid (and uses p to do the work of deciding when that is).
v(D,E,G):-E=1,                  % # base case:
          member(_-_,D),        % # ensure the grid is nonempty
          p(D);                 % # print the grid (and exit)

                                % # otherwise, recursive case:
          F#=E-1,nth(F,D,M),    % # check the last unchecked element
          (
            M=[_];              % # either it's not on the path; or
            M=L-S/R,            % # it's structured correctly, and
            z(L,O,G),           % # it has a valid delta;
            J is F+O,           % # find the outdelta'd element index
            nth(J,D,I/U-T/Q),   % # and the outdelta'd element
            (
              I=O,Q#=R-1,S=T;   % # if not an endpoint, points to next pixel
              K is J+O,         % # else find segment beyond the path:
              R=0,              % # it's an endpoint,
              n(S-T-V),         % # it points to the correct segment,
              y(U,G),           % # ensure we can do NOT comparisons on U
              U\=O,U=\= -O,     % # the line we jump is at right angles
              I=U,              % # the line we jump is straight
              nth(K,D,O/_-V/_)  % # the pixel beyond has a correct indelta,
                                % # and it has the correct segment number
            )
          ),
          v(D,F,G).             % # recurse

% # We use i (init) to set up the k, n tables (k and n are fixed for
% # any run of the program, at least). S is the number of elements that
% # have been removed from K so far (initially 0). To save on characters,
% # we combine k and n into a single predicate n.
i([H|K],S):-K=[]->             % # if this is the last element,
            assertz(n(S-H-0)); % # section 0 comes after S;
            T#=S+1,            % # otherwise, add 1 to S,
            assertz(n(S-H-T)), % # that section comes after S,
            i(K,T).            % # and recurse.

% # We use t (template) to create a template drawing. First argument is
% # the drawing, second argument is the number of rows it has plus 1,
% # third argument is the number of columns it has plus 1.
t([],1,_):-!.
t(D,R,G):-S#=R-1,t(E,S,G),      % # recurse,
          H#=G-1,length(F,H),   % # F is most of this row of the grid
          append(F,[[x]|E],D).  % # form the grid with F + border + E

% # We use s (shrink) to map a coordinate into a value in the range 0, 1, 2, 3.
s(1,2).
s(-1,1).
s(S,T):-S>1->T=3;T=0.
% # We use r (representation) to map a grid cell to a character.
r(I/O-_,C):-s(I,J),s(O,P),N#=J*4+P+1,nth(N,"│┐┌?└─?┌┘?─┐?┘└│",C).
r([X],C):-X\=y->C=10;C=32.
% # We use p (print) to pretty-print a grid.
% # The base case allows us to exit after printing one knot.
p([]).
p([H|T]):-r(H,C),put_code(C),!,p(T).

% # We use g (gridsize) to generate grid sizes.
g(4).
g(G):-g(H),G#=H+1.

% # Main program.
m(K):-i(K,0),                  % # initialize n
      g(G),                    % # try all grid sizes
      t(D,G,G),                % # generate a square knot template, size G
      length(D,L),             % # find its length
      v(D,L,G),                % # verify and print one knot
      % # Technically, this doesn't verify the last element of L, but we know
      % # it's a border/newline, and thus can't be incorrect.
      abolish(n/1).            % # reset n for next run; required by PPCG rules

আমি জিএনইউ প্রোগলজ ডাউনলোড করেছি, আপনার কোডটি একটি টেক্সট ফাইলে অনুলিপি করেছি, এ্যাসিআই-এনকোডেড পিপিএল ফাইল হিসাবে সংরক্ষণ করেছি এবং এম ([0]) নামক কনসোলে
জে আন্তোনিও পেরেজ

আপনি প্রোগ্রাম আরও দক্ষ করতে পারে এমন কোন উপায় আছে কি?
জে আন্তোনিও পেরেজ

আমি সন্দেহ করি প্রোগ্রামটি আরও দক্ষ করে তোলা যেতে পারে, তবে এর কোন সুস্পষ্ট বা সহজ উপায় নেই। বাম থেকে ডান / উপরে থেকে নীচে নাটকে বাদ দিয়ে গিঁটের সাথে সরানোর জন্য মূল্যায়নের আদেশ পরিবর্তন করা সম্ভবত সহায়তা করবে তবে আমি নিশ্চিত না যে এটি কতটা সহায়তা করবে (এবং এটি যথেষ্ট পরিমাণে কোডও হবে, সুতরাং একটি কোড-গল্ফ কার্যকর করা যায় না )।

তুমি বুঝতে পারছ কেন আমি অনিচ্ছা, ঠিক আছে? মানে ... এমনকি সর্বোত্তম কোডটিও পরীক্ষা করা দরকার, এবং আপনার সমাধানটি এত জটিল যে আমি এটি যাচাই করতেও পারি না যে এটি খুব সহজ নট ([[2, 0, 1] নট)) পুনরুত্পাদন করবে।
জে আন্তোনিও পেরেজ

আমি বুঝতে পারি, হ্যাঁ যাইহোক, কোড-গল্ফের মধ্যে এটি আন্তরিকভাবে অন্তর্নিহিত , বিশেষত যখন প্রোলোগের কথা আসে। কোডটি আসলে খুব সহজ, কারণ এটি এত ধীরে ধীরে চলে; একটি জটিল সমস্যা সম্পর্কিত কোড-গল্ফ প্রায় সবসময় একটি ব্রুট-ফোর্স সমাধানের দিকে নিয়ে যায় যা নির্দিষ্টকরণের বিরুদ্ধে সমস্ত সম্ভাব্য ফলাফলগুলি পরীক্ষা করে। প্রোগ্রামটিকে আরও দক্ষ করে তোলার জন্য কিছু করা এটিকে যথেষ্ট দীর্ঘায়িত করবে এবং সম্ভবত এটি সঠিকভাবে বুঝতে এবং সঠিক প্রমাণ করা আরও শক্ত করে তুলবে।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.