سلام دوست عزیز😃👋

به مسابقه «المپیک فناوری: PHP/Laravel» خوش آمدی!

لینک‌های مفید برای شرکت در مسابقه:

هرگونه ارتباط با سایر شرکت‌کنندگان و یا استفاده از ابزارهای تولید کد، مثل chatGPT و... در مسابقات کوئرا ممنوع است و بعد از شناسایی از لیست شرکت‌کنندگان مسابقه حذف می‌شوید.

می‌توانید با هم‌تیمی مشورت کنید و با کمک هم به حل سوالات بپردازید. اگر حداقل یکی از اعضای تیم ارسال پاسخ انجام دهد برای دریافت نمره تیم کافی است.

در طول مسابقه، می‌توانید سؤالات خود را از قسمت «سوال بپرسید» مطرح کنید.

مشورت با هم‌تیمی اوکیه و اگر یکی از اعضای تیم ارسال کنند کافی است تا امتیاز برای کل تیم در نظر گرفته شود.

موفق باشید 😉✌

معینِ دوز و کلک (Laravel)


معین که پس از شکست در طراحی سوالات خوب برای مسابقات برنامه نویسی #المپیک‌فناوری از کار خود در کوئرا، بر‌کنار شده است و در حال حاضر مشغول دوز (Tic-tac-toe یا همان بازی ایکس-او خودمان) بازی است! معین که آدم پر دوز و کلکی است و هیچ کاری را مثل سایر افراد انجام نمی‌دهد، در دوز-بازی هم دوز و کلک جدیدی می‌زند. او بازی دوز را به این شکل تغییر می‌دهد که پس از انجام حرکت چهارم، اولین حرکتی که از هر کدام از بازیکن‌ها باقی مانده بود از بازی پاک می‌شود. معین برای معرفی این بازی به جهانیان قصد دارد تا نسخه‌ی برخطی از آن را با استفاده از لاراول پیاده سازی کند.

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید.

ساختار فایل‌ها
moeine-dooz-o-kalak
├── app
│   ├── Http
│   │   ├── Livewire
│   │   │   ├── XOGame.php
│   ├── Models
│   └── Providers
├── bootstrap
├── config
├── database
├── public
├── resources
│   ├── views
│   │   ├── livewire
│   │   │   └── x-o-game.blade.php
│   │   └── dooz.blade.php
│   └── css
├── routes
│   └── web.php
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
└── vite.config.js
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید php و composer را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.
  • دستور npm install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید. (توجه کنید که این پروژه از Tailwindcss استفاده می‌کند)
  • دستور npm run dev را در مسیر پوشه اصلی پروژه اجرا کنید. در صورتی که این دستور را اجرا نکنید نمی‌توانید ویو‌های ساخته شده با Tailwindcss را مشاهده کنید.
  • برای اجرای تست‌های نمونه، می‌توانید از دستور php artisan test استفاده کنید.

پیاده‌سازی پروژه🔗

در این سوال قرار است شما به سراغ پیاده سازی این بازی هیجان‌انگیز با استفاده از Livewire3 بروید!

جزئیات دقیق‌تر و معرفی بازی جدید معینِ دوزُ کلک

جزئیات دقیق‌تر و معرفی بازی جدید معینِ دوزُ کلک🔗

همانطور که در بخش ابتدایی این سوال گفته شد، بازی معینِ دوزُ کلک یک نسخه خاصی از بازی دوز است که در آن پس از انجام حرکت چهارم، قدیمی‌ترین (ابتدایی‌ترین) حرکتی که همان فرد انجام داده است باید از صفحه بازی حذف شود! به مثال زیر توجه کنید که در آن پس از حرکت چهارم X، حرکت اول او از بازی حذف می‌شود و به این ترتیب جا برای حرکت‌های جدید باز می‌شود. همین شرایط برای بازیکن O و همچنین سایر حرکت‌ها هم صادق است.

  • برد بازی مانند یک دوز کلاسیک، زمانی اتفاق خواهد افتاد که یکی از بازکینان X یا O بتواند یک سطر، ستون و یا یکی از قطر‌های اصلی را با X یا O تماما پر کند.

پیش نمایش بازی

نکته قابل توجه در این نسخه از بازی این است که ممکن است پس از انجام تعدادی حرکت، فرد موقعیت این را داشته باشد که یک سطر، ستون و یا قطر را کامل کند، اما پس از انجام مرحله مورد نظر برای تکمیل خانه‌ها، به جای اینکه یکی از حرکت‌های خارج از آن سطر، ستون و یا قطر جایگزین در تنها خانه باقی مانده برای تکمیل‌شان شود، به دلیل رعایت در ترتیب، یکی از حرکت‌هایی که در همان راستا قرار دارد در این خانه جایگزین شود. در این صورت فرد باید با طی کردن تعدادی مراحل بازی را به وضعیتی برساند که با رعایت ترتیب درست؛ یک راستا کامل شده و فرد بازی را برنده شود.

دموی بخش چلنجینگ بازی

در واقع این نسخه از بازی دوز، یک نسخه دارای حافظه می‌باشد! پس ترتیب حرکت‌های انجام شده هم علاوه بر ماهیت و مکان حرکت انجام شده اهمیت خواهد داشت زیرا این مورد در ترتیب حذف شدن حرکت‌های X یا O از صفحه و برد بازیکن نقش خواهد داشت.

جزئیات و ساختار Route و View بازی

برای دسترسی به این بازی در پروژه اولیه یک Route با آدرس /dooz به صورت پیشفرض تعریف شده است که به ویو dooz متصل شده است. در این مسیردهی و ویو تعریف شده نباید تغییری داده شود.

در فایل مربوط به ویو dooz شما باید کامپوننتی (Component) که از قبل در ساختار پروژه اولیه با نام x-o-game تعریف شده است را استفاده (Include) کنید. این کامپوننت همان بخش اصلی بازی دوز است که قرار است تا اجزای مختلف کامپوننتش را در بخش‌های بعدی این سوال پیاده‌سازی کنید تا در نهایت بازی به درستی اجرا شود.

extensionFromNamelaravel
<?php

use Illuminate\Support\Facades\Route;

Route::get('/dooz', function () {
    return view('dooz');
});
PHP
extensionFromNamelaravel
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>❌ Moeine Dooz O Kalak ⭕</title>
    @vite('resources/css/app.css')
    @livewireStyles
</head>
<body>

    {{--TODO: Include Laravel game component--}}

@livewireScripts
</body>
</html>
PHP

و در نهایت ساختار View مربوط به کامپوننت بازی که در مسیر resources/views/livewire/x-o-game.blade.php قرار گرفته است و باید در ویو dooz.blade.php از آن استفاده شود به شکل زیر است:

extensionFromNamelaravel
<div class="flex flex-col items-center justify-center min-h-screen bg-teal-700">
    <h1 class="text-6xl font-bold text-white mb-8">❌ Moeine Dooz O Kalak ⭕</h1>

    <!-- Input form for player names -->
    <div class="flex flex-col items-center space-y-4">
        <input type="text" placeholder="🏅First Player's name"
               class="px-4 py-2 rounded bg-white text-black text-xl focus:outline-none">
        <input type="text" placeholder="🏅Second Player's name"
               class="px-4 py-2 rounded bg-white text-black text-xl focus:outline-none">
        <button class="bg-cyan-500 text-white font-bold py-2 px-4 rounded hover:bg-cyan-600">
            Start Game 🎮
        </button>
    </div>
    <!-- Input form for player names -->

    <!-- Winner animation section -->
    <div class="absolute inset-0 flex items-start justify-center">
        <div class="confetti-container">
            @for ($i = 0; $i < 18; $i++)
                <div class="confetti-piece"></div>
            @endfor
        </div>
        <div class="text-white text-6xl font-bold animate-bounce scale-125 mt-12 z-50">
            🎉 Winner: [WinnerPlayerName]! 🎉
        </div>
    </div>
    <!-- Winner animation section -->

    <!-- Game board section -->
    <div class="grid grid-cols-3 gap-4 w-64">
            <button class="bg-teal-700 border-4 border-teal-500 aspect-square text-5xl font-bold flex items-center justify-center
                transition-transform transform hover:scale-105 hover:bg-teal-600 focus:outline-none focus:ring-2 focus:ring-yellow-300">
                    <span class="text-gray-300">X</span>
                    <span class="text-yellow-300">O</span>
            </button>
    </div>
    <!-- Game board section -->

    <!-- Current turn section -->
    <div class="mt-6 text-xl text-white">
        🕹 Current Turn:
        <span class="font-bold animate-pulse">[X] - [PlayerName]</span>
    </div>
    <!-- Current turn section -->

    <!-- Leaderboard to track wins -->
    <div class="mt-6 text-xl text-white">
        <div class="font-bold">📊 Leaderboard</div>
        <div>[Player1Name]: [NumberOfWinsPlayer1] win(s)</div>
        <div>[Player2Name]: [NumberOfWinsPlayer2] win(s)</div>
    </div>
    <!-- Leaderboard to track wins -->

</div>
PHP
  • این ساختار صرفا ساختار آماده مربوط به رابط گرافیکی بازی می‌باشد و منطق نمایش المان‌های مختلف آن باید توسط شما در این کامپوننت پیاده‌سازی شود.
ساختار بازی معینِ دوزُ کلک

ورود به بازی🔗

پس از اجرای مسیر /dooz در ابتدا شما با ساختاری مشابه ساختار زیر مواجه می‌شوید، که در آن دو Input از شما دو رشته را به عنوان نام بازیکنان دریافت می‌کنند. سپس پس از فشردن دکمه Start Game 🎮 باید برسی شود که در صورتی که هر دو نام وارد شده بودند بازی آغاز شود. نیازی به انجام هیچ اعتبارسنجی‌ای برای نام‌های ورودی نیست؛ صرفا این دو رشته نباید مقادیر خالی باشند.

تصویر اول سوال معین دوز و کلک

پس از وارد کردن نام‌ها باید با ساختاری مشابه ساختار زیر مواجه شوید، که در آن علاوه بر جدول 333 * 3 بازی، یک جدول امتیاز برای دو نامی که وارد شده وجود خواهد داشت که مجموع امتیازات هر فرد را مشخص می‌کند.

تصویر دوم سوال معین دوز و کلک

دموی بازی اول

پس از انجام بازی با هر تعداد مرحله، با توجه به موارد نوشته شده در بخش جزئیات دقیق‌تر و معرفی بازی ممکن است بازی برنده‌ای داشته باشد. در صورتی که فردی با انجام حرکتی موجب پیروزی شد، باید مطابق تصویر زیر، 🎉 Winner: [PlayerName]! 🎉 در بالای صفحه همراه با انیمیشن مورد نظر نمایش داده شده، جدول و وضعیت بازی ریست شده و همچنین به تعداد برد‌های فردی که برنده بازی شده یکی اضافه شود.

تصویر سوم سوال معین دوز و کلک

مورد قابل توجه این است که بازی را همیشه X شروع می‌کند اما بازیکنان هر دفعه به صورت یکی در میان نقش X و O را بر عهده می‌گیرند تا بازی عدالت بیشتری داشته باشد. همچنین بازی را فردی شروع می‌کند که نامش در ابتدای ورود به بازی به عنوان نام نفر اول وارد شده است. برای مثال، اگر دوین نام اول و معین نام دوم باشد، در بازی اول دوین X و معین O و در بازی دوم، معین X و دوین O خواهد بود و ترتیب چرخشی به همین صورت برای باقی بازی‌ها ادامه خواهد داشت. اما در تمامی حالات شروع کننده بازی X است و صرفا فرد شروع‌کننده تغییر خواهد کرد.

با توجه به موارد گفته شده در بخش‌های بالا، شما باید ساختار کامپوننت Livewire ای XOGame را که در ساختار پروژه اولیه در مسیر app/Livewire/XOGame.php قرار دارد را مطابق با ساختار زیر پیاده سازی کنید:

extensionFromNamelaravel
<?php

namespace App\Livewire;

use Livewire\Component;

class XOGame extends Component
{
    public $board = [];
    public $current_turn = 'X';
    public $last_winner = null;

    public $player1_name;
    public $player2_name;
    public $player1_wins = 0;
    public $player2_wins = 0;

    public $name_submitted = false;

    public function mount()
    {
        // TODO: Implement
    }

    public function submitNames()
    {
       // TODO: Implement 
    }

    public function resetBoard()
    {
        // TODO: Implement
    }

    public function makeMove($index)
    {
        // TODO: Implement
    }

    public function render()
    {
        // TODO: Implement
    }
}
PHP

توضیحات ساختار و ویژگی‌های این کامپوننت به شکل زیر است:

  • متغیر board: این متغیر همان‌طور که از اسمش پیداست ساختار جدول را در خود ذخیره می‌کند. هر کدام از خانه‌های این جدول می‌توانند یکی از مقادیر X، O و یا null باشند. این متغیر یک آرایه یک‌بعدی می‌باشد که اندیس‌های شماره 0 تا 8 اش نشان دهنده خانه‌های جدول بازی هستند.
  • متغیر current_turn: این متغیر نشان‌دهنده نوبت فعلی می‌باشد که می‌تواند یکی از مقادیر X و یا O را داشته باشد.
  • متغیر last_winner: این متغیر مشخص می‌کند که آخرین فردی که برنده بازی شده است چه کسی بوده است. این متغیر در ابتدا مقداری برابر با null دارد اما بلافاصله پس از بردن بازی توسط یکی از X و یا O مقدار آن را ذخیره‌سازی می‌کند.
  • متغیر‌های player1_name و player2_name: این دو متغیر نام دو بازیکن را دریافت و ذخیره‌سازی می‌کنند.
  • متغیرهای player1_wins و player2_wins: این دو متغیر تعداد برد هر کدام از بازیکن‌ها را مشخص می‌کنند. این مقدار باید پس از برد هر فرد بروزرسانی شود و به صورت زنده در صفحه بازی نمایش داده شود.
  • متغیر name_submitted: این متغیر یک متغیر بولی است که پس از وارد شدن نام بازیکنان مقدارش از false ابتدایی به true تغییر پیدا می‌کند.

توابعی که شما باید در این سوال پیاده‌سازی کنید به شکل زیر هستند:

  • تابع mount: این تابع در واقع همان تابع سازنده کامپوننت خواهد بود.
  • تابع submitNames: این تابع باید برسی کند که در صورتی که نام بازیکنان وارد شده بود، مقدار متغیر name_submitted را به true تغییر دهد. در ویو کامپوننت این مورد برسی شده و در صورتی که نام بازیکنان وارد شده بود دیگر بخش وارد کردن نام و شروع بازی نباید نمایش داده شود.
  • تابع resetBoard: این تابع وضعیت بازی را ریست می‌کند. توجه کنید که با ریست وضعیت بازی صرفا جدول و نوبت بازی X یا O ریست می‌شود و تغییری در امتیاز بازیکنان داده نمی‌شود. در واقع این تابع پس از مشخص شدن هر وضعیت برد اجرا خواهد شد تا بتوان بازی را به تعداد دلخواهی بار با شرایط گفته شده انجام داد.
  • تابع makeMove: این تابع در هر مرحله با فشردن بر روی یکی از خانه‌های جدول اجرا می‌شود. هر خانه که یکی از اندیس‌ها 0 تا 8 را داراست (خانه‌های جدول هر بار از سمت چپ به راست اندیس‌دهی می‌شوند، یعنی اندیس‌های سطر اول برابر با 0 1 2 و اندیس‌های سطر دوم برابر با 3 4 5 خواهند بود) مهره تعیین شده در current_turn در خانه مشخص شده از جدول جایگزین می‌شود.
  • تابع render: این تابع کامپوننت بازی را رندر می‌کند.

آن‌چه باید آپلود کنید🔗

  • توجه: شما می‌توانید هر تعداد تابع یا متغیر کمکی را در ساختار کامپوننت بازی (یا همان کلاس XOGame) پیاده‌سازی کنید، اما توابع و متغیر‌هایی که در مورد آن‌ها در سوال توضیح داده شده است نباید تغییری داشته باشند. تغییر در ساختار ورودی توابع یا نام توابع و متغیر‌های تعریف شده باعث عدم دریافت نمره از سمت داور خودکار خواهد شد.
  • توجه: تمامی موارد مربوط به استایل‌های بازی در پروژه اولیه از قبل قرار گرفته اند و شما نیازی به پیاده‌سازی هیچ‌گونه استایلی ندارید. در این سوال که از Tailwindcss برای طراحی رابط کاربری استفاده شده است، موارد مورد نیاز مربوط به کامپوننت بازی در مسیر View این کامپوننت در مسیر resources/views/livewire/x-o-game.blade.php قرار گرفته اند، اما شما نیاز پیدا خواهید کرد تا مانند ساختار گفته شده منطق نمایش آن‌ها را پیاده‌سازی کنید.
  • توجه: پیاده‌سازی منطق نمایش در ویو‌ی کامپوننت resources/views/livewire/x-o-game.blade.php در سیستم داوری مورد تست قرار خواهد گرفت، لذا از تغییر نام یا افرودن فواصل کمتر یا بیشتر در متن المان‌هایی که در اختیار شما قرار داده شده مانند دکمه‌ها و یا متن‌های نمایش داده شده اکیدا خودداری کنید. ایجاد تغییرات منجر‌ به عدم دریافت نمره از سیستم داوری خواهد شد.
  • توجه: پس از اعمال تغییرات، کل پروژه به غیر از پوشه‌ی vendorو node_modules را Zip کرده و آپلود کنید.
  • توجه: نام فایل ZIP اهمیتی ندارد.
ارسال پاسخ برای این سؤال
در حال حاضر شما دسترسی ندارید.