معین که پس از شکست در طراحی سوالات خوب برای مسابقات برنامه نویسی #المپیکفناوری از کار خود در کوئرا، برکنار شده است و در حال حاضر مشغول دوز (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 اهمیتی ندارد.
ارسال پاسخ برای این سؤال