অ্যারে ভিত্তিক হেক্স ম্যাপে আমি কীভাবে পিক্সেল হেক্স স্থানাঙ্কে পেতে পারি?


10

আমি একটি হেক্স ম্যাপের জন্য সমন্বিত ফাংশন করার জন্য একটি পিক্সেল তৈরি করার চেষ্টা করছি তবে আমি গণিতটি সঠিকভাবে পাচ্ছি না, আমি যা চেষ্টা করি তা কিছুটা দূরে বলে মনে হয় এবং আমি যে উদাহরণগুলি পেয়েছি তা গোলাকার কেন্দ্রিক মানচিত্রের ভিত্তিতে তৈরি হয়েছিল।

'অ্যারে ভিত্তিক' বলতে আমি হেক্স্সকে যেভাবে অর্ডার করা হয়েছে তার অর্থ পিক দেখুন।

আমি সবচেয়ে সঠিক ফলাফলটি পেয়েছি নিম্নলিখিত কোডটি সহ, তবে এটি এখনও বন্ধ রয়েছে এবং মানগুলি যত বেশি উত্থাপন করে খারাপ হয়:

public HexCell<T> coordsToHexCell(float x, float y){
    final float size = this.size; // cell size
    float q = (float) ((1f/3f* Math.sqrt(3) * x - 1f/3f * y) / size);
    float r = 2f/3f * y / size;
    return getHexCell((int) r, (int) q);
}

Hexmap

উপরের বাম দিকে 0,0 দিয়ে স্ক্রিন শুরু হয়, প্রতিটি ঘর এর কেন্দ্র জানে।

আমার কেবলমাত্র পর্দার স্থানাঙ্কগুলি হেক্স স্থানাঙ্কে অনুবাদ করার একটি উপায়। আমি এটা কিভাবে করতে পারি?

উত্তর:


12

অনেকগুলি হেক্স্স সমন্বয় ব্যবস্থা রয়েছে। "অফসেট" পদ্ধতির একটি আয়তক্ষেত্রাকার মানচিত্র সংরক্ষণের জন্য দুর্দান্ত তবে হেক্স অ্যালগরিদমগুলি আরও জটিল বলে।

আমার সালে হেক্স গ্রিড নির্দেশিকা (যা আমি বিশ্বাস করি আপনি ইতিমধ্যে খুঁজে পেয়েছেন), আপনার তুল্য সিস্টেম থাকে তাদের লেবেল বলা হয় "এমনকি-R", আপনি ব্যতীত r,qপরিবর্তে q,r। আপনি এই পদক্ষেপগুলি সহ পিক্সেল অবস্থানগুলিকে হেক্স স্থানাঙ্কে রূপান্তর করতে পারেন:

  1. এই বিভাগে বর্ণিত অ্যালগরিদম ব্যবহার করে পিক্সেল অবস্থানগুলিকে অক্ষীয় হেক্স স্থানাঙ্কে রূপান্তর করুন । এটি আপনার ফাংশনটি করে। তবে আপনার আরও একটি পদক্ষেপ নেওয়া দরকার।
  2. সেই অক্ষীয় স্থানাঙ্কগুলি ভগ্নাংশ। তাদের নিকটতম হেক্স পর্যন্ত গোল করা দরকার। আপনার কোডে আপনি ব্যবহার করেন (int)r, (int)qতবে এটি কেবল স্কোয়ারের জন্য কাজ করে; হেক্সেসের জন্য আমাদের আরও জটিল গোলাকার পদ্ধতির প্রয়োজন। রূপান্তর r, qকরার ঘনক্ষেত্র ব্যবহার স্থানাঙ্ক ঘনক্ষেত্র থেকে অক্ষীয় সূত্র এখানে । তারপরে এখানেhex_round ফাংশনটি ব্যবহার করুন
  3. এখন আপনার কাছে কিউব স্থানাঙ্কের একটি পূর্ণসংখ্যা সেট রয়েছে । আপনার মানচিত্রটি কিউব নয়, "এমনকি-আর" ব্যবহার করে, তাই আপনাকে ফিরে রূপান্তর করতে হবে। ব্যবহার করুন এমনকি-R অফসেট ঘনক্ষেত্র থেকে সূত্র এখানে

এটিকে আরও স্পষ্ট করার জন্য আমাকে পিক্সেলটি হেক্স স্থানাংক বিভাগে পুনরায় লিখতে হবে। দুঃখিত!

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


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

2
@ এমিটপ: আমি আপনার গাইডকে ভালবাসি, কয়েক বছর আগে আমি যখন ষড়ভুজ গ্রিড জেনারেটর লিখেছিলাম তখন আমি তাতে হোঁচট খেয়েছি। আপনি যদি আগ্রহী হন তবে আমার সমাধানটি এখানে রয়েছে: ওভারফ্লো স্ট্যাক করুন - সমন্বিত সিস্টেমের সাথে ষড়ভুজ গ্রিড তৈরি করতে অ্যালগরিদম
মিঃ পলিহর্ল

1
পিক্সেল স্থানাঙ্কের উত্স কোথায়? অফসেট স্থানাঙ্কে 0,0 হেক্সাগনের কেন্দ্রে?
অ্যান্ড্রু

1
@ অ্যান্ড্রু হ্যাঁ হেক্স স্থানাঙ্কে রূপান্তরটি চালানোর আগে আপনি পিক্সেল স্থানাঙ্কে উত্সটি স্থানান্তর করতে পারেন।
amitp

9

আমার মতে এই সমস্যাটি পরিচালনা করার দুটি উপায় রয়েছে।

  1. আরও ভাল সমন্বয় ব্যবস্থা ব্যবহার করুন। আপনি কীভাবে হেক্সেসকে নম্বর দিচ্ছেন সে সম্পর্কে আপনি যদি চালাক হন তবে আপনি নিজের উপর অঙ্কটি আরও সহজ করে তুলতে পারেন। অমিত প্যাটেলের ষড়ভুজ গ্রিডগুলির সুনির্দিষ্ট উল্লেখ রয়েছে। আপনি এই পৃষ্ঠায় অক্ষীয় স্থানাঙ্কের সন্ধান করতে চাইবেন ।

  2. ইতিমধ্যে সমাধান করে এমন কারও কাছ থেকে কোড ধার করুন। আমার কিছু কোড রয়েছে যা কার্যকর হয়, যা আমি ওয়েসনথ উত্স থেকে যুদ্ধ থেকে উত্তোলন করেছি । মনে রাখবেন যে আমার সংস্করণে শীর্ষে হেক্সসের সমতল অংশ রয়েছে, তাই আপনাকে এক্স এবং ওয়াই পরিবর্তন করতে হবে।


6

আমি মনে করি মাইকেল ক্রিস্টোফিকের উত্তরটি সঠিক, বিশেষত অমিত প্যাটেলের ওয়েবসাইট উল্লেখ করার জন্য, তবে আমি হেক্স গ্রিডের সাথে আমার নবজাতকের দৃষ্টিভঙ্গিটি ভাগ করে নিতে চেয়েছিলাম।

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

আমার রেন্ডার ক্লাসে আমার এটি এমন একটি পদ্ধতিতে সংজ্ঞায়িত করা হয়েছিল যা আমাকে যে হেক্সের পাশের দৈর্ঘ্য সেট করতে চেয়েছিল সেটি সেট করতে দিয়েছিল। এখানে দেখানো হয়েছে কারণ এই মানগুলির কয়েকটি হিক্স স্থানাঙ্ক কোডে পিক্সেলটিতে উল্লেখ করা হয়েছিল।

                this.s = Side; //Side length
                this.h = Math.floor(Math.sin(30 * Math.PI / 180) * this.s);
                this.r = Math.floor(Math.cos(30 * Math.PI / 180) * this.s);
                this.HEXWIDTH = 2 * this.r;
                this.HEXHEIGHT = this.h + this.s;
                this.HEXHEIGHT_CENTER = this.h + Math.floor(this.s / 2);

মাউস ইনপুট ক্লাসে, আমি এমন একটি পদ্ধতি তৈরি করেছি যা স্ক্রিন x এবং y স্থানাঙ্ককে গ্রহণ করেছে এবং পিক্সেলের মধ্যে থাকা হেক্স স্থানাঙ্কের সাথে একটি বস্তু ফিরিয়ে দিয়েছি ides * নোট করুন যে আমার কাছে একটি জাল "ক্যামেরা" ছিল তাই রেন্ডার পজিশনের অফসেটগুলিও অন্তর্ভুক্ত করা হয়েছে।

    ConvertToHexCoords:function (xpixel, ypixel) {
        var xSection = Math.floor(xpixel / ( this.Renderer.HEXWIDTH )),
            ySection = Math.floor(ypixel / ( this.Renderer.HEXHEIGHT )),
            xSectionPixel = Math.floor(xpixel % ( this.Renderer.HEXWIDTH )),
            ySectionPixel = Math.floor(ypixel % ( this.Renderer.HEXHEIGHT )),
            m = this.Renderer.h / this.Renderer.r, //slope of Hex points
            ArrayX = xSection,
            ArrayY = ySection,
            SectionType = 'A';
        if (ySection % 2 == 0) {
            /******************
             * http://www.gamedev.net/page/resources/_/technical/game-programming/coordinates-in-hexagon-based-tile-maps-r1800
             * Type A Section
             *************
             *     *     *
             *   *   *   *
             * *       * *
             * *       * *
             *************
             * If the pixel position in question lies within the big bottom area the array coordinate of the
             *      tile is the same as the coordinate of our section.
             * If the position lies within the top left edge we have to subtract one from the horizontal (x)
             *      and the vertical (y) component of our section coordinate.
             * If the position lies within the top right edge we reduce only the vertical component.
             ******************/
            if (ySectionPixel < (this.Renderer.h - xSectionPixel * m)) {// left Edge
                ArrayY = ySection - 1;
                ArrayX = xSection - 1;
            } else if (ySectionPixel < (-this.Renderer.h + xSectionPixel * m)) {// right Edge
                ArrayY = ySection - 1;
                ArrayX = xSection;
            }
        } else {
            /******************
             * Type B section
             *********
             * *   * *
             *   *   *
             *   *   *
             *********
             * If the pixel position in question lies within the right area the array coordinate of the
             *      tile is the same as the coordinate of our section.
             * If the position lies within the left area we have to subtract one from the horizontal (x) component
             *      of our section coordinate.
             * If the position lies within the top area we have to subtract one from the vertical (y) component.
             ******************/
            SectionType = 'B';
            if (xSectionPixel >= this.Renderer.r) {//Right side
                if (ySectionPixel < (2 * this.Renderer.h - xSectionPixel * m)) {
                    ArrayY = ySection - 1;
                    ArrayX = xSection;
                } else {
                    ArrayY = ySection;
                    ArrayX = xSection;
                }
            } else {//Left side
                if (ySectionPixel < ( xSectionPixel * m)) {
                    ArrayY = ySection - 1;
                    ArrayX = xSection;
                } else {
                    ArrayY = ySection;
                    ArrayX = xSection - 1;
                }
            }
        }
        return {
            x:ArrayX + this.Main.DrawPosition.x, //Draw position is the "camera" offset
            y:ArrayY + this.Main.DrawPosition.y
        };
    },

অবশেষে এখানে আমার প্রকল্পটির একটি স্ক্রিনশট রেন্ডারের ডিবাগ চালু আছে। এটি লাল রেখাগুলি দেখায় যেখানে কোডটি হ্যাক্স স্থানাঙ্কের সাথে টাইপএ বনাম টাইপবি কোষগুলির জন্য পরীক্ষা করে এবং কোষের রূপরেখা এখানে চিত্র বর্ণনা লিখুন
আশা করে যে এটি কিছুটিকে সহায়তা করে।


4

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

public HexCell<T> coordsToHexCell(float x, float y){
    HexCell<T> cell;
    HexCell<T> result = null;
    float distance = Float.MAX_VALUE;
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            cell = getHexCell(r, c);

            final float dx = x - cell.getX();
            final float dy = y - cell.getY();
            final float newdistance = (float) Math.sqrt(dx*dx + dy*dy);

            if (newdistance < distance) {
                distance = newdistance;
                result = cell;
            }           
        }
    }
    return result;
}

3
এটি একটি যুক্তিসঙ্গত পন্থা। আপনি সেগুলি স্ক্যান করার পরিবর্তে সারি / কলের একটি ছোট পরিসর স্ক্যান করে এটিকে গতি বাড়িয়ে তুলতে পারেন। এটি করার জন্য আপনাকে হেক্স কোথায় রয়েছে সে সম্পর্কে মোটামুটি ধারণা দরকার। যেহেতু আপনি অফসেট গ্রিড ব্যবহার করছেন, আপনি কলামগুলির মধ্যে ফাঁক করে x এবং সারিগুলির মধ্যে ফাঁক করে y কে ভাগ করে মোটামুটি অনুমান করতে পারেন। তারপরে সমস্ত কলাম 0…cols-1এবং সমস্ত সারি স্ক্যান করার পরিবর্তে 0…rows-1আপনি স্ক্যান করতে পারেন col_guess - 1 … col_guess+1এবং row_guess - 1 … row_guess + 1। এটি কেবল 9 টি হেক্সস তাই এটি দ্রুত এবং মানচিত্রের আকারের উপর নির্ভর করে না।
amitp

3

অমিত প্যাটেলের ওয়েব সাইটে পোস্ট কৌশলগুলির মধ্যে একটি # সি বাস্তবায়নের সাহস এখানে দেওয়া হয়েছে (আমি নিশ্চিত জাভায় অনুবাদ করা কোনও চ্যালেঞ্জ হবে না):

public class Hexgrid : IHexgrid {
  /// <summary>Return a new instance of <c>Hexgrid</c>.</summary>
  public Hexgrid(IHexgridHost host) { Host = host; }

  /// <inheritdoc/>
  public virtual Point ScrollPosition { get { return Host.ScrollPosition; } }

/// <inheritdoc/>
public virtual Size  Size           { get { return Size.Ceiling(Host.MapSizePixels.Scale(Host.MapScale)); } }

/// <inheritdoc/>
public virtual HexCoords GetHexCoords(Point point, Size autoScroll) {
  if( Host == null ) return HexCoords.EmptyCanon;

  // Adjust for origin not as assumed by GetCoordinate().
  var grid    = new Size((int)(Host.GridSizeF.Width*2F/3F), (int)Host.GridSizeF.Height);
  var margin  = new Size((int)(Host.MapMargin.Width  * Host.MapScale), 
                         (int)(Host.MapMargin.Height * Host.MapScale));
  point      -= autoScroll + margin + grid;

  return HexCoords.NewCanonCoords( GetCoordinate(matrixX, point), 
                                   GetCoordinate(matrixY, point) );
}

/// <inheritdoc/>
public virtual Point   ScrollPositionToCenterOnHex(HexCoords coordsNewCenterHex) {
  return HexCenterPoint(HexCoords.NewUserCoords(
          coordsNewCenterHex.User - ( new IntVector2D(Host.VisibleRectangle.Size.User) / 2 )
  ));
}

/// <summary>Scrolling control hosting this HexGrid.</summary>
protected IHexgridHost Host { get; private set; }

/// <summary>Matrix2D for 'picking' the <B>X</B> hex coordinate</summary>
Matrix matrixX { 
  get { return new Matrix(
      (3.0F/2.0F)/Host.GridSizeF.Width,  (3.0F/2.0F)/Host.GridSizeF.Width,
             1.0F/Host.GridSizeF.Height,       -1.0F/Host.GridSizeF.Height,  -0.5F,-0.5F); } 
}
/// <summary>Matrix2D for 'picking' the <B>Y</B> hex coordinate</summary>
Matrix matrixY { 
  get { return new Matrix(
            0.0F,                        (3.0F/2.0F)/Host.GridSizeF.Width,
            2.0F/Host.GridSizeF.Height,         1.0F/Host.GridSizeF.Height,  -0.5F,-0.5F); } 
}

/// <summary>Calculates a (canonical X or Y) grid-coordinate for a point, from the supplied 'picking' matrix.</summary>
/// <param name="matrix">The 'picking' matrix</param>
/// <param name="point">The screen point identifying the hex to be 'picked'.</param>
/// <returns>A (canonical X or Y) grid coordinate of the 'picked' hex.</returns>
  static int GetCoordinate (Matrix matrix, Point point){
  var pts = new Point[] {point};
  matrix.TransformPoints(pts);
      return (int) Math.Floor( (pts[0].X + pts[0].Y + 2F) / 3F );
  }

প্রকল্পের বাকী অংশগুলি উপরে উল্লিখিত ম্যাট্রিক্সআইএনটি 2 ডি এবং ভেক্টরআইন্ট 2 ডি ক্লাস সহ ওপেন সোর্স হিসাবে এখানে উপলভ্য:
http://hexgridutilities.codeplex.com/

যদিও উপরের বাস্তবায়নটি ফ্ল্যাট-টপড হেক্সেসের জন্য, হেক্সগ্রিড ইউটিলিটিস লাইব্রেরিতে গ্রিড স্থানান্তর করার বিকল্প অন্তর্ভুক্ত রয়েছে।


0

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

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

জ্যামিতি

আপনি যদি টাইলের প্রস্থের চতুর্থাংশের কলাম এবং একটি টাইলের অর্ধেক উচ্চতার সারিগুলি সহ গ্রিডে পয়েন্টগুলি রাখেন তবে আপনি এই প্যাটার্নটি পাবেন:

উপরে বর্ণিত

আপনি যদি পরে চেকবোর্ড প্যাটার্নে (স্কিপ if column % 2 + row % 2 == 1) প্রতিটি দ্বিতীয় বিন্দুতে এড়াতে কোডটি পরিবর্তন করেন তবে আপনি এই প্যাটার্নটি দিয়ে শেষ করবেন:

উপরে বর্ণিত

বাস্তবায়ন

সেই জ্যামিতিটি মাথায় রেখে আপনি একটি 2 ডি অ্যারে তৈরি করতে পারেন (ঠিক যেমন আপনি একটি বর্গাকার গ্রিডের মতো) গ্রিডের x, yপ্রতিটি পয়েন্টের জন্য স্থানাঙ্কগুলি সংরক্ষণ করে (প্রথম চিত্র থেকে) - এরকম কিছু:

points = []
for x in numberOfColumns
    points.push([])
    for y in numberOfRows
        points[x].push({x: x * widthOfColumn, y: y * heightOfRow})

নোট: স্বাভাবিক হিসাবে, যখন আপনি একটি গ্রিড তৈরি করছেন প্রায় পয়েন্ট (বদলে বিন্দু স্থাপন নিজেদের পয়েন্ট), আপনি মূল (থেকে একটি কলামের অর্ধেক প্রস্থ বিয়োগ অফসেট প্রয়োজন xএবং অর্ধেক থেকে সারির উচ্চতা y)।

এখন আপনার 2 ডি অ্যারে ( points) আরম্ভ করা হয়েছে, আপনি যেমন বর্গ গ্রিডে যাচ্ছিলেন ঠিক তেমনভাবে মাউসের নিকটতম পয়েন্টটি আবিষ্কার করতে পারেন, কেবল দ্বিতীয় চিত্রটিতে প্যাটার্নটি তৈরি করতে প্রতিটি অন্যান্য পয়েন্ট উপেক্ষা করতে হবে:

column, row = floor(mouse.x / columnWidth), floor(mouse.y / rowHeight)
point = null if column % 2 + row % 2 != 1 else points[column][row]

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.