**علی** پس از جابهجا کردن مرزهای طراحی مسابقات برنامهنویسی در کوئرا، اینبار تصمیم گرفته تا **رشته جدیدی** را به *#المپیکفناوری* پردیس اضافه کند که از یک بازی قدیمی که در ایام کودکی بسیار به آن علاقه داشته به شیوه جدیدی در آن استفاده میکند. این بازی مورد علاقه علی، [**بازی معروف ۲۰۴۸**](https://en.wikipedia.org/wiki/2048_%28video_game%29) میباشد که در دورانی جزو **محبوبترین** بازیهای فکری بود. شما در این سوال به پیادهسازی **یک نسخه شگفتانگیز** از این بازی خواهید پرداخت که قابلیتهای عجیبی دارد که در نسخه کلاسیک این بازی یافت **نمیشود**.
![دموی بازی ۲۰۴۸ شگفتانگیز](https://quera.org/qbox/view/eRDXWCgIZr/contest_new2048_game_main.png)
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/255961/) دانلود کنید.
<details class="yellow">
<summary>
**ساختار فایلها**
</summary>
```plaintext
2048-shegeft-angiz
├── app
│ ├── Http
│ │ ├── Livewire
│ │ │ ├── <mark class="orange" title="این فایل باید پیادهسازی شود">Game2048.php</mark>
│ ├── Models
│ └── Providers
├── bootstrap
├── config
├── database
├── public
├── resources
│ ├── views
│ │ ├── livewire
│ │ │ └── <mark class="orange" title="این فایل باید پیادهسازی شود">game2048.blade.php</mark>
│ │ └── <mark class="orange" title="این فایل باید پیادهسازی شود">2048.blade.php</mark>
│ └── css
├── routes
│ └── web.php
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
└── vite.config.js
```
</details>
<details class="grey">
<summary>
**راهاندازی پروژه**
</summary>
**برای اجرای پروژه، باید `php` و `composer` را از قبل نصب کرده باشید.**
+ ابتدا پروژهی اولیه را دانلود و از حالت فشرده خارج کنید.
+ دستور `composer install` را در پوشهی اصلی پروژه برای نصب نیازمندیها اجرا کنید.
+ دستور `npm install` را در پوشهی اصلی پروژه برای نصب نیازمندیها اجرا کنید. *(توجه کنید که این پروژه از* [*Tailwindcss*](https://tailwindcss.com/) *استفاده میکند)*
+ دستور `npm run dev` را در مسیر پوشه اصلی پروژه اجرا کنید. در صورتی که این دستور را اجرا نکنید نمیتوانید ویوهای ساخته شده با *Tailwindcss* را مشاهده کنید.
+ برای اجرای تستهای نمونه، میتوانید از دستور `php artisan test` استفاده کنید.
</details>
# پیادهسازی پروژه
در این سوال قرار است شما به سراغ پیاده سازی این بازی **شگفتانگیز** با استفاده از [*Livewire3*](https://livewire.laravel.com) بروید! بخشهایی از این بازی از پیش برای شما پیادهسازی شده است و شما صرفا قرار است تا به سراغ پیادهسازی برخی موارد گفته شده در سوال بروید. **توجه کنید که این سوال جزئیات فراوانی دارد پس در خواندن متن سوال دقت لازم را داشته باشید.**
<details class="green">
<summary>
**جزئیات دقیقتر و معرفی بازی** _۲۰۴۸_
</summary>
# جزئیات دقیقتر و معرفی بازی _۲۰۴۸_
![بازی 2048](https://quera.org/qbox/view/lx5t4UzIpz/2048demo.png)
[**بازی معروف ۲۰۴۸**](https://en.wikipedia.org/wiki/2048_%28video_game%29) روی یک جدول شطرنجی **۴×۴** ساده با کاشیهای **شمارهدار** بازی میشود که وقتی بازیکن آنها را با استفاده از **چهار کلید جهتدار** حرکت میدهد، میلغزند. در هر نوبت، **یک کاشی** بهطور تصادفی در نقطهای خالی روی تابلو ظاهر میشود که مقدار آن **۲ یا ۴** است. کاشیها تا جایی که **ممکن است** در جهتِ انتخاب شده میلغزند؛ تا زمانی که کاشی دیگر یا لبهٔ شبکهٔ شطرنجی متوقفشان نکند. اگر در حین حرکت، دو کاشی با **شمارهٔ یکسان** بههم بخورند، آنگاه در یک کاشی که **ارزشش برابر با مجموع ارزش دو کاشی برخوردی** است، **ادغام** میشود. کاشی بهدستآمده **نمیتواند** در همان حرکت، دوباره با کاشی دیگری ادغام شود *(به عنوان مثال اگر در یک جهت سه عدد کاشی با شماره* `4` *یافت میشد، پس از انجام یک حرکت دو عدد از آنها با یکدیگر ادغام میشود و مقدار* `8` *را تشکیل میدهند اما کاشی سوم که مقدار* `4` *دارد ادغام نشده باقی میماند)*. کاشیهای با امتیاز بالاتر، درخششی روشنتر از خود ساطع میکنند.
![دموی بازی 2048](https://quera.org/qbox/view/aF0enWkXWG/contest_2048demo-gif.gif)
+ در بخش بالا میتوانید دمویی از این بازی را مشاهده کنید. همچنین شما میتوانید این بازی را از طریق [**این لینک**](https://play2048.co/) به **صورت آنلاین** بر روی مرورگر خود بازی کنید.
</details>
<details class="blue">
<summary>
**جزئیات و ساختار `Route` و `View` بازی**
</summary>
برای دسترسی به این بازی در پروژه اولیه یک `Route` با آدرس `/2048` به صورت پیشفرض تعریف شده است که به ویو `2048` متصل شده است. در این مسیردهی و ویو تعریف شده نباید تغییری داده شود.
در فایل مربوط به ویو `2048` شما باید **کامپوننتی** *(Component)* که از قبل در ساختار پروژه اولیه با نام `game2048` تعریف شده است را **استفاده** *(Include)* کنید. این کامپوننت همان بخش اصلی بازی دوز است که قرار است تا اجزای مختلف کامپوننتش را در بخشهای بعدی این سوال پیادهسازی کنید تا در نهایت بازی به درستی اجرا شود.
```php laravel web.php
<?php
use Illuminate\Support\Facades\Route;
Route::get('/2048', function () {
return view('2048');
});
```
```php laravel dooz.blade.php
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🕹2048 Shegeft Angiz🎮</title>
<link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" rel="stylesheet" type="text/css" />
@vite('resources/css/app.css')
@livewireStyles
</head>
<body>
{{--TODO: Include Laravel game component--}}
@livewireScripts
</body>
</html>
```
و در نهایت ساختار `View` مربوط به کامپوننت بازی که در مسیر `resources/views/livewire/game2048.blade.php` قرار گرفته است و باید در ویو `2048.blade.php` از آن استفاده شود به شکل زیر است:
```php laravel x-o-game.blade.php
<div class="max-w-xl mx-auto text-center text-gray-100 bg-gray-800 p-8 rounded-lg shadow-lg my-8">
<div class="flex justify-between items-center mb-6">
<!-- Player score section -->
<div class="bg-gray-700 text-white p-2 rounded mt-6">
<span class="block text-xs font-vazirmatn">امتیاز</span>
<span class="text-lg font-vazirmatn">0</span>
</div>
<!-- Player score section -->
<div class="text-white">
<h1 class="text-8xl font-bold mb-1 font-vazirmatn">۲۰۴۸</h1>
<p class="my-2 mx-2 text-gray-400 font-vazirmatn">خود را برای رسیدن به <strong>۲۰۴۸</strong> به چالش بکشید! </p>
</div>
<!-- Highest score section -->
<div class="bg-gray-700 text-white p-2 rounded mt-6">
<span class="block text-xs font-vazirmatn">بهترین</span>
<span class="text-lg font-vazirmatn">0</span>
</div>
<!-- Highest score section -->
</div>
<div class="flex justify-center items-center mb-6">
<!-- Reset game button -->
<button class="font-vazirmatn bg-gradient-to-r from-blue-500 to-blue-700 text-white py-2 px-4 rounded-lg shadow-lg hover:from-gray-600 hover:to-blue-800 transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center">
<svg class="w-6 h-6 text-blue-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 18V6l8 6-8 6Z"/>
</svg>
شروع بازی جدید
</button>
<!-- Reset game button -->
</div>
<div class="my-4">
<hr class="border-t border-white" />
</div>
<!-- Game message Section -->
<div class="mt-4 text-center text-lg text-green-600 font-vazirmatn">
<!-- Show game message -->
</div>
<!-- Game message Section -->
<!-- Game grid Section -->
<div class="grid grid-cols-4 gap-4 bg-gray-700 p-4 rounded-lg relative mt-8 justify-items-center" dir="ltr">
<!-- Grid cells Section -->
<div class="text-4xl h-24 w-24 flex items-center justify-center rounded-lg shadow-inner my-1
@if ($cell === 0) bg-gray-800 text-transparent
@elseif ($cell === 2) bg-gray-200 text-black
@elseif ($cell === 4) bg-gray-300 text-black
@elseif ($cell === 8) bg-yellow-200 text-black
@elseif ($cell === 16) bg-yellow-300 text-black
@elseif ($cell === 32) bg-yellow-400 text-white
@elseif ($cell === 64) bg-orange-300 text-white
@elseif ($cell === 128) bg-orange-400 text-white
@elseif ($cell === 256) bg-orange-500 text-white
@elseif ($cell === 512) bg-red-300 text-white
@elseif ($cell === 1024) bg-red-400 text-white
@elseif ($cell === 2048) bg-red-500 text-white
@endif">
</div>
<!-- Grid cells Section -->
<!-- Gameover and restart Section -->
<div class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-70 rounded-lg" dir="rtl">
<h2 class="text-3xl font-bold text-white mb-4 font-vazirmatn"></h2>
<button class="mt-4 px-4 py-2 bg-white text-gray-800 rounded-lg font-vazirmatn">شروع بازی جدید</button>
</div>
<!-- Gameover and restart Section -->
</div>
<!-- Game grid Section -->
<div class="flex justify-between items-center mt-6">
<!-- Undo action button -->
<button class="font-vazirmatn bg-gradient-to-r from-gray-500 to-gray-700 text-white py-2 px-4 rounded-lg shadow-lg hover:from-gray-600 hover:to-gray-800 transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-gray-500 flex items-center">
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 18V6l8 6-8 6Z"/>
</svg>
برگشت حرکت (0)
</button>
<!-- Undo action button -->
<!-- Delete tile button -->
<button class="font-vazirmatn bg-gradient-to-r from-red-500 to-red-700 text-white py-2 px-4 rounded-lg shadow-lg hover:from-red-600 hover:to-red-800 transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-red-500 flex items-center">
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
حذف کاشی (0)
</button>
<!-- Delete tile button -->
<!-- Swap tile button -->
<button class="font-vazirmatn bg-gradient-to-r from-yellow-500 to-yellow-700 text-white py-2 px-4 rounded-lg shadow-lg hover:from-yellow-600 hover:to-yellow-800 transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-yellow-500 flex items-center">
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4M20 12l-4 4m4-4l-4-4" />
</svg>
تعویض دو کاشی (0)
</button>
<!-- Swap tile button -->
</div>
<script>
document.addEventListener('keydown', function (event) {
let direction = '';
switch (event.key) {
case 'ArrowUp':
direction = 'up';
@this.move('up');
break;
case 'ArrowDown':
direction = 'down';
@this.move('down');
break;
case 'ArrowLeft':
direction = 'left';
@this.move('left');
break;
case 'ArrowRight':
direction = 'right';
@this.move('right');
break;
}
});
</script>
</div>
```
- این ساختار صرفا ساختار آماده مربوط به رابط گرافیکی بازی میباشد و منطق نمایش المانهای مختلف آن باید توسط شما در این کامپوننت پیادهسازی شود.
</details>
<details class="yellow">
<summary>
**ساختار کلی بازی و وضعیتهای برد و باخت**
</summary>
## ساختار کلی بازی
ساختار کلی این بازی بسیار شبیه به [**نسخه اصلی بازی ۲۰۴۸**](https://en.wikipedia.org/wiki/2048_%28video_game%29) میباشد. در هر وضعیت آغازین ۲ عدد کاشی **به صورت تصادفی** در دو تا از خانههای جدول قرار میگیرند. **این مقادیر تصادفی باید حتما مقدار ۲ و یا ۴ باشد.** پس از وضعیت آغازین فقط در هر مرتبه بازی در صورتی که جدول دچار تغییراتی شود، یک کاشی جدید دیگر که دارای مقدار ۲ و یا ۴ است به صورت تصادفی در جایی از جدول اضافه خواهد شد. **در صورتی که هیچ تغییری در جدول ایجاد نشود، هیچ کاشی جدیدی در بازی اضافه نمیشود.**
**همچنین توجه داشته باشید** که در صورت استفاده از قابلیتهای شگفتانگیز بازی نظیر برگشت به حرکت قبل و یا حذف کاشی و تعویض دو کاشی **هیچ کاشی جدیدی** به جدول اضافه **نخواهد** شد.
![دموی بازی ۲۰۴۸ ساخت بازی جدید](https://quera.org/qbox/view/ObjQyhCBpm/contest_game2048_final-gif-1.gif)
## وضعیت برد
**یک وضعیت برد** زمانی برای شما اتفاق میافتد که شما بتوانید با تعدادی حرکت **حداقل یک کاشی با ارزش ۲۰۴۸** ایجاد کنید. در این صورت بازی به پایان میرسد و علاوه بر نمایش پیام **"هوراااا :) شما بازی را بردید!"** باید از کاربر دعوت شود تا دوباره بازی جدیدی را آغاز کند. *(توجه کنید که متن مشخص شده برای وضعیت برد نباید تغییری کند و باید دقیقا عبارت گفته شده باشد.)*
![وضعیت برد بازی ۲۰۴۸](https://quera.org/qbox/view/1HthxVBW9W/contest_game2048_game-demo-3.png)
## وضعیت باخت
**یک وضعیت باخت** زمانی برای شما اتفاق میافتد که شما پس از انجام تعدادی حرکت تمام صفحه را با کاشیهایی مقادیر مختلف پر کردید که دیگر **نمیتوانید** هیچ عمل ادغام دو کاشیای را انجام دهید. در این حالت شما هر حرکتی انجام دهید **هیچ تغییری در صفحه ایجاد نمیشود**، همچنین شما **قادر به ساخت هیچ کاشیای با ارزش ۲۰۴۸ نیز نشدهاید**. در این حالت شما بازی را خواهید باخت و به شکل زیر پیام **"متاسفیم :( شما بازی را باختید!"** برای شما نشان داده خواهد شد و از شما دعوت به عمل میآید تا بازی جدیدی را آغاز کنید. *(توجه کنید که متن مشخص شده برای وضعیت باخت نباید تغییری کند و باید دقیقا عبارت گفته شده باشد.)*
![وضعیت باخت بازی ۲۰۴۸](https://quera.org/qbox/view/hHoLtgLaWr/contest_game2048_game-demo-2.png)
**موردی که قابل توجه این است** که صفحهی بازی، امتیاز و تمامی مقادیر دیگر مثل بیشترین امتیاز یا تعداد نوبت باقی مانده از قابلیتهای شگفتانگیز باید در تمامی مراحل در قالب **نشست** *(Session)* ذخیره شود تا در صورتی که صفحه بسته شد، بازی قابلیت ادامه دادن در آینده را داشته باشد.
**همچنین توجه کنید** که **امتیاز فعلی** و **بیشترین امتیاز** همواره به صورت زنده در صفحه بازی بروزرسانی میشود. امتیاز هر بازی در ابتدا **صفر** است و در **صورتی که دو کاشی با یکدیگر ادغام شوند**، **امتیاز به اندازه مقدار کاشی جدید که پس از ادغام بدست آمده است اضافه خواهد شد**. همچنین در صورتی که امتیاز فعلی بازی از بیشترین امتیاز بدست آمده بیشتر بود باید مقدارش با آن جایگزین شود تا **همواره بیشترین امتیاز کسب شده** در تمام بازیها در صفحه بازی نمایش داده شود.
</details>
<details class="green">
<summary>
**ساختار بخش قابلیتهای شگفتانگیز بازی**
</summary>
بخش متفاوت و شگفت انگیز این بازی نسبت به حالت کلاسیک بازی ۲۰۴۸ در این بخش خلاصه میشود. به تصویر زیر دقت کنید:
![دموی بخش شگفتانگیز بازی](https://quera.org/qbox/view/HOSRyokg7A/game-demo-6.png)
بخش قابلیتهای شگفتانگیز بازی از سه بخش "برگشت حرکت"، "حذف کاشی" و "تعویض دو کاشی" تشکیل شده است که عملکردی آنها به شکل زیر است:
- **بخش "برگشت حرکت":** با فشردن این دکمه بازی به یک حرکت قبل بر میگردد. در واقع این دکمه همان دکمه آندو (Undo) بازی میباشد که در صورتی که کاربر حرکت اشتباهی را انجام دهد میتواند جهت جبران آن از این قابلیت استفاده کند.
- **بخش "حذف کاشی":** با فشردن این دکمه کاربر میتواند با انتخاب یکی از کاشیهای صفحه آن را به کل از صفحه حذف نماید. این کار اجازه میدهد تا با حذف کاشی یا کاشیهای مزاحم کاربر بتواند بازی را به نفع خود جلو ببرد.
- **بخش "تعویض دو کاشی"**: با فشردن این دکمه، کاربر باید از صفحه بازی دو کاشی را انتخاب کند. دو کاشی انتخاب شده جای خود را با یکدیگر تغییر میدهند. از این قابلیت میتوان در جهت برد بازی در حالاتی که نیاز است دو کاشی با ارزش یکسان در کنار یکدیگر قرار بگیرند تا ادغام شوند و کاشی با ارزشتری را بسازند استفاده کرد.
تمامی این قابلیتهای شگفتانگیز به کاربر اجازه میدهد تا **فرصت جبران حرکت اشتباه** و یا **تغییر بازی به وضعیتی** را داشته باشد که **مطلوبتر** است و **باعث کسب امتیاز بیشتری** خواهد شد.
**توجه شود** که کاربر در کل **نشست** *(Session)* خود تنها **اجازه ۲ نوبت استفاده** از هر کدام از این قابلیتها را خواهد داشت و در صورتی که این نوبتها به اتمام برسد، کاربر دیگر اجازه استفاده از این قابلیتها را نخواهد داشت. همچنین هر مرتبه که کاربر بتواند **یک کاشی جدید با ارزش ۵۱۲** بسازد، **یک نوبت جدید** برای استفاده از هر کدام از این قابلیتهای شگفتانگیز به او افزوده خواهد شد. **حداکثر** مقدار نوبتهای مجاز برای تمامی این قابلیتها، **۲ نوبت** میباشد و **کاربر میتواند این نوبتها را برای باقی بازیهای خود نیز نگهداری کند**. *(یعنی این نوبتها در هر نشست تعریف میشوند نه در هر بازی و با اتمام بازی تعداد نوبتها ریست نخواهد شد)*
![دموی بخش شگفتانگیز بازی ۲۰۴۸](https://quera.org/qbox/view/ZqrE9h2ak6/contest_game2048_final-gif-2.gif)
</details>
با توجه به موارد گفته شده در بخشهای بالا، شما باید ساختار *کامپوننت Livewire ای* `Game2048` را که در ساختار پروژه اولیه در مسیر `app/Livewire/Game2048.php` قرار دارد را مطابق با ساختار زیر پیاده سازی کنید:
```php laravel app/Livewire/Game2048.php
<?php
namespace App\Livewire;
use Livewire\Component;
class Game2048 extends Component
{
public $grid = [];
public $score = 0;
public $highScore = 0;
public $undoUses = 2;
public $swapUses = 2;
public $deleteTileUses = 2;
public function mount()
{
// TODO: Implement
}
public function render()
{
// TODO: Implement
}
public function move($direction)
{
// TODO: Implement
}
public function undoAction()
{
// TODO: Implement
}
public function deleteTile($x, $y)
{
// TODO: Implement
}
public function selectTileForSwap($x, $y)
{
// TODO: Implement
}
public function swapTiles()
{
// TODO: Implement
}
public function resetGame()
{
// TODO: Implement
}
}
```
### توضیحات ساختار و ویژگیهای این کامپوننت به شکل زیر است:
- **متغیر** `grid`**:** این متغیر همانطور که از اسمش پیداست ساختار جدول را در خود ذخیره میکند. هر کدام از خانههای این جدول میتوانند `0` *(به معنی خانهی خالی و پوچ بدون کاشی)* و یا **توانی از دو** باشند که مقدار ارزش کاشی آن خانه را مشخص خواهد کرد. توجه کنید که اندیسهای جدول **باید** همگی از `0` شروع شوند.
- **متغیر** `score`**:** این متغیر نشاندهنده امتیاز فعلی کاربر در بازی میباشد. امتیاز کاربر و جدول بازی با هر بار ریلود شدن صفحه **نباید** تغییری کنند.
- **متغیر** `highScore`**:** این متغیر مشخص میکند که بالاترین امتیاز کسب شده در بازی توسط کاربر در تمامی بازیهایی که انجام داده است چه مقداری است.
- **متغیرهای** `undoUses`، `swapUses` **و** `deleteTileUses`**:** این متغیرها همانطور که از نامشان پیداست نشاندهنده تعداد هر کدام از ویژگیهای شگفتانگیز است. همانطور که پیشتر توضیح داده شد؛ هر کاربر در تمام **نشست** خود تنها اجازه `2` بار استفاده از هر کدام از این ویژگیها را دارد. همچنین فرصت استفاده از این ویژگیها با توجه به توضیحات گفته شده میتواند **تحت شرایطی** افزایش یابد.
### توابعی که شما باید در این سوال پیادهسازی کنید به شکل زیر هستند:
- **تابع** `mount`**:** این تابع در واقع همان تابع سازنده کامپوننت خواهد بود.
- **تابع** `move`**:** این تابع تقریبا مهمترین بخش بازی میباشد. یک آرگومان ورودی دریافت میکند که یکی از مقادیر `up`، `down`، `left` و `right` است که نشان دهنده جهت حرکت است. این مقدار توسط *اسکریپت Js* که در انتهای ویوی بازی قرار دارد و مسئول تشخیص دکمههای حرکتی بازی است به این تابع ورودی داده خواهد شد.
- **تابع** `undoAction`**:** این تابع مسئول برگشت حرکت به حرکت قبلی است و هیچ آرگمانی را به عنوان ورودی دریافت نمیکند. در صورتی که تعداد فرصتهای استفاده از این قابلیت **صفر نباشد**، با فراخوانی این تابع ساختار جدول بازی به یک حرکت قبل از حرکت فعلی باز خواهد گشت.
- **تابع** `deleteTile`**:** با هر بار اجرا شدن این تابع که دو مقدار ورودی `x` و `y` دارد که به ترتیب موقعیت **سطر** و **ستون** خانهای که قصد داریم کاشی از آن حذف شود را مشخص میکنند، در صورتی که آن کاشی وجود داشته باشد *(مقدار 0 نداشته باشد)* و تعداد فرصتهای استفاده از این قابلیت **صفر نباشد**، کاشی مورد نظر را **حذف** خواهد کرد.
- **تابع** `selectTileForSwap`**:** با هر بار اجرا شدن این تابع که دو مقدار ورودی `x` و `y` دارد که به ترتیب موقعیت **سطر** و **ستون** خانهای که قصد داریم کاشیاش را انتخاب کنیم را مشخص میکنند، در صورتی که آن کاشی وجود داشته باشد *(مقدار 0 نداشته باشد)* آن را انتخاب خواهد کرد. انتخاب شدن به صورت ذخیرهسازی موقعیت این کاشی خواهد بود تا با اجرای دوبارهی آن بتوان کاشی دومی را نیز انتخاب و موقعیت آن را ذخیرهسازی کرد.
- **تابع** `swapTiles`**:** این تابع با استفاده از مقادیر ذخیرهسازی شده با استفاده از `selectTileForSwap` در هنگام فراخوانی در صورتی که تعداد فرصتهای استفاده از این قابلیت **صفر نباشد**، موقعیت دو کاشی را با هم تعویض میکند. این تابع هیج آرگومان ورودیای **ندارد**.
- **تابع** `render`**:** این تابع کامپوننت بازی را رندر میکند.
# آنچه باید آپلود کنید
+ **توجه**: شما میتوانید هر تعداد تابع یا متغیر کمکی را در ساختار کامپوننت بازی (یا همان کلاس `Game2048`) پیادهسازی کنید، اما توابع و متغیرهایی که در مورد آنها در سوال توضیح داده شده است **نباید** تغییری داشته باشند. تغییر در ساختار ورودی توابع یا نام توابع و متغیرهای تعریف شده باعث **عدم دریافت نمره** از سمت داور خودکار خواهد شد.
+ **توجه**: تمامی موارد مربوط به استایلهای بازی در پروژه اولیه از قبل قرار گرفته اند و شما نیازی به پیادهسازی هیچگونه استایلی ندارید. در این سوال که از *Tailwindcss* برای طراحی رابط کاربری استفاده شده است، موارد مورد نیاز مربوط به کامپوننت بازی در مسیر `View` این کامپوننت در مسیر `resources/views/livewire/game2048.blade.php` قرار گرفته اند، اما شما نیاز پیدا خواهید کرد تا مانند ساختار گفته شده منطق نمایش آنها را پیادهسازی کنید.
+ **توجه**: پیادهسازی منطق نمایش در ویوی کامپوننت `resources/views/livewire/game2048.blade.php` در سیستم داوری مورد تست قرار خواهد کرفت، لذا از تغییر نام یا افرودن فواصل کمتر یا بیشتر در متن المانهایی که در اختیار شما قرار داده شده مانند دکمهها و یا متنهای نمایش داده شده **اکیدا خودداری کنید. ایجاد تغییرات منجربه عدم دریافت نمره از سیستم داوری خواهد شد.**
+ **توجه**: پس از اعمال تغییرات، کل پروژه به غیر از پوشهی `vendor`و `node_modules` را _Zip_ کرده و آپلود کنید.
+ **توجه**: نام فایل _Zip_ اهمیتی ندارد.