معین که پس از شکست در طراحی سوالات خوب برای مسابقات برنامه نویسی #المپیکفناوری از کار خود در کوئرا، برکنار شده است و در حال حاضر مشغول دوز (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
راهاندازی پروژه
برای اجرای پروژه، باید 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 و View بازیبرای دسترسی به این بازی در پروژه اولیه یک Route با آدرس /dooz به صورت پیشفرض تعریف شده است که به ویو dooz متصل شده است. در این مسیردهی و ویو تعریف شده نباید تغییری داده شود.
در فایل مربوط به ویو dooz شما باید کامپوننتی (Component) که از قبل در ساختار پروژه اولیه با نام x-o-game تعریف شده است را استفاده (Include) کنید. این کامپوننت همان بخش اصلی بازی دوز است که قرار است تا اجزای مختلف کامپوننتش را در بخشهای بعدی این سوال پیادهسازی کنید تا در نهایت بازی به درستی اجرا شود.
<?php
use Illuminate\Support\Facades\Route;
Route::get('/dooz', function () {
return view('dooz');
});
<!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>
و در نهایت ساختار View مربوط به کامپوننت بازی که در مسیر resources/views/livewire/x-o-game.blade.php قرار گرفته است و باید در ویو dooz.blade.php از آن استفاده شود به شکل زیر است:
<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>
- این ساختار صرفا ساختار آماده مربوط به رابط گرافیکی بازی میباشد و منطق نمایش المانهای مختلف آن باید توسط شما در این کامپوننت پیادهسازی شود.
ساختار بازی معینِ دوزُ کلک
ورود به بازی
پس از اجرای مسیر /dooz در ابتدا شما با ساختاری مشابه ساختار زیر مواجه میشوید، که در آن دو Input از شما دو رشته را به عنوان نام بازیکنان دریافت میکنند. سپس پس از فشردن دکمه Start Game 🎮 باید برسی شود که در صورتی که هر دو نام وارد شده بودند بازی آغاز شود. نیازی به انجام هیچ اعتبارسنجیای برای نامهای ورودی نیست؛ صرفا این دو رشته نباید مقادیر خالی باشند.

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


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

مورد قابل توجه این است که بازی را همیشه X شروع میکند اما بازیکنان هر دفعه به صورت یکی در میان نقش X و O را بر عهده میگیرند تا بازی عدالت بیشتری داشته باشد. همچنین بازی را فردی شروع میکند که نامش در ابتدای ورود به بازی به عنوان نام نفر اول وارد شده است. برای مثال، اگر دوین نام اول و معین نام دوم باشد، در بازی اول دوین X و معین O و در بازی دوم، معین X و دوین O خواهد بود و ترتیب چرخشی به همین صورت برای باقی بازیها ادامه خواهد داشت. اما در تمامی حالات شروع کننده بازی X است و صرفا فرد شروعکننده تغییر خواهد کرد.
با توجه به موارد گفته شده در بخشهای بالا، شما باید ساختار کامپوننت Livewire ای XOGame را که در ساختار پروژه اولیه در مسیر app/Livewire/XOGame.php قرار دارد را مطابق با ساختار زیر پیاده سازی کنید:
<?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
}
}
توضیحات ساختار و ویژگیهای این کامپوننت به شکل زیر است:
- متغیر
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 اهمیتی ندارد.
ارسال پاسخ برای این سؤال