انتقل إلى اللغز
في أحد الأيام، برزت في ذهني ذكرى لعبة ألغاز صغيرة من طفولتي، وهي عبارة عن أحجية منزلق حيث يتم وضع 15 بلاطة مربعة في إطار في ترتيب 4 × 4 من الخلايا مع ترك مساحة واحدة فارغة. تسمح مجموعة من النتوءات والأخاديد الموجودة على حواف كل بلاطة والإطار للبلاطات بالانزلاق فوق بعضها البعض أثناء تثبيت البلاط في الإطار. في أي وقت، يمكن لأي بلاطة مجاورة للمساحة الحرة أن تتحرك إلى تلك المساحة، وإلا يتم منع البلاطات من الحركة. يؤدي نقل البلاط إلى المساحة الحرة إلى ترك مساحة خالية جديدة من حيث جاء البلاط ويمكن بعد ذلك نقل بلاط آخر إلى تلك المساحة الجديدة. تتمثل الفكرة في تحريك البلاط بشكل متكرر بهذه الطريقة لترتيب البلاط في ترتيب محدد مسبقًا.
يبدو أن هذا يسمى "اللغز 15" وكان موجودًا منذ سبعينيات القرن التاسع عشر. يؤدي البحث في الويب إلى عرض عدد من الاستجمام المكتوب بمجموعة متنوعة من لغات البرمجة، ويوجد بالفعل العديد من المقالات هنا على dev.to بما في ذلك https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n وhttps://dev.to/xzanderzone/make-a-slider-puzzle-in-java-script-83m وhttps://dev.to/claurcia/slide-puzzle-5c55، كل ذلك في JavaScript وhttps:/ /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj في Go. كما يتم تقديمه أيضًا باعتباره تحديًا جيدًا للمبتدئين الذين يتعلمون JavaScript.
ما أثار اهتمامي هو فكرة أنه يجب أن يكون قابلاً لإعادة الإنشاء على الويب باستخدام أي لغة برمجة على الإطلاق! أي تنفيذ باستخدام HTML وCSS خالصين فقط. لذلك أقدمها أدناه. الحل الوسط الوحيد الذي كان عليّ القيام به هو أن الألعاب العشرة المقدمة تحتوي على مواضع بداية ثابتة تم تبديلها مسبقًا.
لهذا الأمر المحدد مسبقًا هو إظهار صورة مكتملة.
المبدأ الأساسي لهذا التنفيذ هو أن كل بلاطة تحتفظ بسجل حالة لمكان وجودها داخل الإطار. لا توجد طرق عديدة لتغيير الحالة والاحتفاظ بها في HTML وCSS، ولكن الأكثر شيوعًا هو "اختراق مربع الاختيار" ويستفيد منه هذا التنفيذ بشكل مكثف. بالنسبة لأي شخص ليس على دراية باختراق مربع الاختيار، عند النقر فوق عنصر
لذلك يحتوي كل مربع على زوج من مجموعات أزرار الاختيار لكل منها أربعة أزرار اختيار. تحتفظ إحدى هاتين المجموعتين بموضع التجانب في المحور X والأخرى بموضعه في المحور Y. (أو الموضع الأفقي والموضع الرأسي على التوالي، إذا كنت تفضل ذلك.) يتم منح كل قطعة من المربعات الخمسة عشر في البداية مجموعة مختلفة من إحداثيات X وY عبر أزرار الاختيار الخاصة بها بحيث يشغل كل منها خلية مختلفة في الإطار.
يتم وضع المربعات في البداية في الخلية العلوية اليسرى للإطار ثم يتم نقلها داخل الإطار عبر CSS لقياس حالة أزرار الاختيار عن طريق تطبيق تحويل ترجمة عليها:
/* "X" refers to the X-axis cell positions, "Y" to the Y-axis cell positions. * 0, 1, 2, 3 refers to the position on that axis, * 0 = left and top, 3 = right and bottom respectively. */ .tile:has(.X0:checked~.Y0:checked) { transform: translate(0%, 0%); } .tile:has(.X0:checked~.Y1:checked) { transform: translate(0%, 100%); } .tile:has(.X0:checked~.Y2:checked) { transform: translate(0%, 200%); } .tile:has(.X0:checked~.Y3:checked) { transform: translate(0%, 300%); } .tile:has(.X1:checked~.Y0:checked) { transform: translate(100%, 0%); } /* and so on for the remainder of the sixteen combinations */
يحتوي المربع أيضًا على ثمانية عناصر تسمية، تتوافق مع أزرار الاختيار الثمانية. يتم وضع كل تسمية بشكل مطلق فوق بعضها البعض ويملأ كل منها المربع بالكامل. التسميات شفافة، وتم إعدادها في البداية بحيث لا تستجيب للنقرات والنقرات عن طريق تعيين أحداث المؤشر: لا شيء عليها جميعًا.
الخطوة التالية هي أن تقوم محددات CSS بتحديد مكان الخلية الفارغة. يتم ذلك عن طريق الحذف، وهي الخلية التي لا يتم تمثيل إحداثيات X وY الخاصة بها بواسطة زوج مجموعة أزرار الاختيار لأي من المربعات الخمسة عشر.
على سبيل المثال، إذا كان هذا يطابق:
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
فيجب أن تكون الخلية الفارغة حاليًا في خلية الزاوية العلوية اليسرى. كرر هذا لكل خلية من الخلايا الستة عشر وسوف تتطابق واحدة منها بالضبط.
بمجرد الانتهاء من ذلك، يمكن التعرف على الخلايا المجاورة للخلية الفارغة. إذا كانت الخلية الفارغة في زاوية، فهناك بالضبط قطعتان من البلاط يمكنهما الانتقال إلى تلك الخلية، وإلا، إذا كانت الخلية الفارغة مقابل أحد جوانب الإطار، فهناك ثلاثة بلاطات يمكن أن تتحرك داخل الخلية، وإلا فإن الخلية الفارغة يجب أن تكون الخلية واحدة من الخلايا الأربع الوسطى، وهناك أربع مربعات يمكن الانتقال إليها. بالنسبة لكل من هذه المربعات، فإن إحدى التسميات الثمانية للبلاطات ستنشط زر الاختيار الصحيح اللازم لنقل المربع إلى الخلية الفارغة. يتم تمكين هذه التسمية عن طريق تعيين قيمة أحداث المؤشر مرة أخرى إلى تلقائي. وعلى سبيل المثال:
/* Top, left corner */ .frame:not(:has(.tile .X0:checked ~ .Y0:checked)) { :is( .tile:has(.X0:checked ~ .Y1:checked) label.Y0, .tile:has(.X1:checked ~ .Y0:checked) label.X0 ) { pointer-events: auto; } } /* right most cell of row two */ .frame:not(:has(.tile .X1:checked ~ .Y3:checked)) { :is( .tile:has(.X1:checked ~ .Y2:checked) label.Y3, .tile:has(.X0:checked ~ .Y3:checked) label.X1, .tile:has(.X2:checked ~ .Y3:checked) label.X1 ) { pointer-events: auto; } } /* second cell from left on row three */ .frame:not(:has(.tile .X2:checked ~ .Y1:checked)) { :is( .tile:has(.X2:checked ~ .Y0:checked) label.Y1, .tile:has(.X2:checked ~ .Y2:checked) label.Y1, .tile:has(.X1:checked ~ .Y1:checked) label.X2, .tile:has(.X3:checked ~ .Y1:checked) label.X2 ) { pointer-events: auto; } }
الخطوة الأخيرة من اللعبة هي تحديد وقت حل اللغز. هذه ببساطة حالة للتحقق من أن جميع المربعات الخمسة عشر تحتوي على أزرار اختيار المحور X وY المتوقعة مضبوطة على الموضع "المحلول".
/* Each tile is assigned a letter "a" to "o". * The puzzle is solved when the tiles are in alphabetical order * reading left to right and top to bottom */ .frame:has(.a .X0:checked ~ .Y0:checked):has(.b .X1:checked ~ .Y0:checked):has( .c .X2:checked ~ .Y0:checked ):has(.d .X3:checked ~ .Y0:checked):has(.e .X0:checked ~ .Y1:checked):has( .f .X1:checked ~ .Y1:checked ):has(.g .X2:checked ~ .Y1:checked):has(.h .X3:checked ~ .Y1:checked):has( .i .X0:checked ~ .Y2:checked ):has(.j .X1:checked ~ .Y2:checked):has(.k .X2:checked ~ .Y2:checked):has( .l .X3:checked ~ .Y2:checked ):has(.m .X0:checked ~ .Y3:checked):has(.n .X1:checked ~ .Y3:checked):has( .o .X2:checked ~ .Y3:checked ) ~ .options .success { display: block; }
والباقي تجميلي. يتم الانزلاق من خلال انتقال بسيط للتحويل الموصوف أعلاه
.tile { transition: 0.5s transform; @media (prefers-reduced-motion) { transition: none; } }
ويظهر كل مربع جزءًا من صورة اللعبة باستخدام حجم الخلفية وموضع الخلفية
.tile { background-size: 400%; } #board1 .tile { background-image: url("https://alohci.net/image/dev.to/slidergame/mullermarc-k7bQqdUf954-unsplash.webp"); } .a { background-position: 0% 0%; } .b { background-position: 33.333% 0%; } .c { background-position: 66.667% 0%; } .d { background-position: 100% 0%; } .e { background-position: 0% 33.333%; } /* and so on for the remaining tiles */
وهناك مجموعة واحدة من أزرار الاختيار لاختيار أي من الألعاب العشرة التي تريد لعبها.
لتشغيل اللعبة، ما عليك سوى النقر أو الضغط على المربع الذي تريد نقله إلى الخلية الفارغة.
لقد قمت أيضًا بتوفير وضع "مجرد" لإظهار أحرف التجانب وأزرار الاختيار التي قد تساعد في فهم كيفية عمل HTML وCSS.
إذًا، هذه هي لعبة الألغاز المكتملة. واسمحوا لي أن أعرف أي ردود فعل لديك.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3