نیما در این روزهای کرونایی حوصلهاش به شدت سر رفته. از این رو، تصمیم گرفته است تا با کمک دوست صمیمیاش، محمدرضا، یک وبسایت ساده بسازد که در آن بتوان XO بازی کرد. قرار است نیما API این بازی را طراحی کند و محمدرضا فرانت کار را پیش ببرد. اخیراً نیما درگیر امتحانات پایانترمش شده و میخواهد این وبسایت تا چند روز دیگر آماده شود. بنابراین، او از شما خواسته است تا API این بازی را پیادهسازی کنید.
جزئیات پروژه
پروژهی اولیه را از این لینک دانلود کنید.
ساختار فایلها
xo
├── app
│ ├── Console
│ │ └── Kernel.php
│ ├── Exceptions
│ │ └── Handler.php
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── API
│ │ │ │ ├── AuthController.php
│ │ │ │ └── GameController.php
│ │ │ └── Controller.php
│ │ ├── Middleware
│ │ │ ├── Authenticate.php
│ │ │ ├── EncryptCookies.php
│ │ │ ├── PreventRequestsDuringMaintenance.php
│ │ │ ├── RedirectIfAuthenticated.php
│ │ │ ├── TrimStrings.php
│ │ │ ├── TrustHosts.php
│ │ │ ├── TrustProxies.php
│ │ │ └── VerifyCsrfToken.php
│ │ └── Kernel.php
│ ├── Models
│ │ ├── Game.php
│ │ ├── Move.php
│ │ └── User.php
│ └── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── bootstrap
│ ├── cache
│ │ ├── packages.php
│ │ ├── routes-v7.php
│ │ └── services.php
│ └── app.php
├── config
│ ├── app.php
│ ├── auth.php
│ ├── broadcasting.php
│ ├── cache.php
│ ├── cors.php
│ ├── database.php
│ ├── filesystems.php
│ ├── hashing.php
│ ├── logging.php
│ ├── mail.php
│ ├── queue.php
│ ├── services.php
│ ├── session.php
│ └── view.php
├── database
│ ├── factories
│ │ └── UserFactory.php
│ ├── migrations
│ │ ├── 2014_10_12_000000_create_users_table.php
│ │ ├── 2014_10_12_100000_create_password_resets_table.php
│ │ ├── 2019_08_19_000000_create_failed_jobs_table.php
│ │ ├── 2021_01_05_094004_create_games_table.php
│ │ └── 2021_01_05_095752_create_moves_table.php
│ ├── seeders
│ │ └── DatabaseSeeder.php
│ └── database.sqlite
├── public
│ ├── favicon.ico
│ ├── index.php
│ ├── robots.txt
│ └── web.config
├── resources
│ ├── css
│ │ └── app.css
│ ├── js
│ │ ├── app.js
│ │ └── bootstrap.js
│ ├── lang
│ │ └── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ └── validation.php
│ └── views
│ └── welcome.blade.php
├── routes
│ ├── api.php
│ ├── channels.php
│ ├── console.php
│ └── web.php
├── storage
│ ├── app
│ │ └── public
│ ├── framework
│ │ ├── cache
│ │ ├── sessions
│ │ ├── testing
│ │ └── views
│ ├── logs
│ │ └── laravel.log
│ ├── oauth-private.key
│ └── oauth-public.key
├── tests
│ ├── Feature
│ │ └── ExampleTest.php
│ ├── Unit
│ │ └── ExampleTest.php
│ ├── CreatesApplication.php
│ └── TestCase.php
├── README.md
├── artisan
├── composer.json
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
راهاندازی پروژه
برای اجرای پروژه، باید php
و composer
را از قبل نصب کرده باشید.
- ابتدا پروژهی اولیه را دانلود و از حالت فشرده خارج کنید.
- دستور
composer install
را در پوشهی اصلی پروژه برای نصب نیازمندیها اجرا کنید. - دستور
php artisan migrate
را برای پیکربندی کامل پایگاه داده اجرا کنید. - دستور
php artisan passport:install
را برای پیکربندی Laravel Passport اجرا کنید.
برای احراز هویت در این پروژه از Laravel Passport استفاده شده است. همچنین، برای پایگاه داده از SQLite استفاده شده است.
مدلها
این پروژه شامل ۳ مدل به شرح زیر است:
- مدل
User
:
نام فیلد | تعریف |
---|---|
id |
شناسهی کاربر |
username |
نام کاربری |
email |
آدرس ایمیل |
password |
رمز عبور |
- مدل
Game
:
نام فیلد | تعریف |
---|---|
id |
شناسهی بازی |
host_id |
شناسهی کاربر میزبان |
opponent_id |
شناسهی حریف |
is_host_turn |
یک boolean که بیانگر این است که الآن نوبت میزبان است یا خیر (مقدار پیشفرض آن false است)؛ مقدار آن در صورتی که بازی تمام شده باشد اهمیتی ندارد. |
status |
یک enum با مقدار پیشفرض pending به این معنا که بازی در انتظار تأیید است. اگر مقدار آن rejected باشد، یعنی حریف درخواست بازی را رد کرده است. اگر ongoing باشد، یعنی بازی در حال انجام است. اگر win باشد، یعنی میزبان برنده شده است. اگر lose باشد، یعنی حریف برنده شده است. اگر tie باشد، یعنی بازی مساوی شده است. |
- مدل
Move
:
نام فیلد | تعریف |
---|---|
id |
شناسهی حرکت |
game_id |
شناسهی بازی |
position |
یک عدد در بازهی 1 تا 9 که بیانگر موقعیت حرکت است |
is_by_host |
یک boolean که بیانگر این است که این حرکت توسط میزبان صورت گرفته است یا خیر |
دو مورد زیر باید در مدلها پیادهسازی شوند:
- متد
games
در مدلUser
را طوری پیادهسازی کنید که با اجرای متدget
روی نتیجهی آن، بتوان آرایهای از بازیهایی که کاربر در آنها نقش میزبان یا حریف دارد را در اختیار داشت. - متد
getBoardAttribute
در مدلGame
را طوری پیادهسازی کنید که صفحهی بازی را در قالب یک آرایهی ۳×۳ برگرداند. خانههای پرشده توسط شروعکنندهی بازی باید باX
و خانههای پرشده توسط میزبان بازی باید باO
نمایش داده شوند. خانههای خالی نیز باید با حرف_
نمایش داده شوند. مثلاً اگر در یک بازی ابتدا حریف خانهی 9 را پر کند، سپس میزبان خانهی 5 را پر کند و در ادامه حریف خانهی 1 را پر کند، این متد باید چنین چیزی را برگرداند:
[
['X', '_', '_'],
['_', 'O', '_'],
['_', '_', 'X']
]
مسیرها
دو route زیر به کنترلر API\AuthController
متصل هستند و باید پیادهسازی شوند:
- ثبتنام (
POST /register
): سه فیلدusername
،email
وpassword
باید در بدنهی درخواست موجود باشند. همچنین، دو فیلدusername
وemail
باید در جدولusers
یکتا باشند. در صورتی که ورودی شرایط لازم را نداشتند، خطاهای پیشفرض Validator لاراول را در قالب JSON برگردانید. در غیر اینصورت، یک آرایه شامل کلیدtoken
با مقدار توکن تولیدشده توسط Laravel Passport را در پاسخ برگردانید. - ورود (
POST /login
): دو فیلدusername
وpassword
باید در بدنهی درخواست موجود باشند. در صورتی که ورودی شرایط لازم را نداشتند، خطاهای پیشفرض Validator لاراول را در قالب JSON برگردانید. اگر نام کاربری یا رمز عبور نادرست بود، یک آرایه شامل کلیدerror
با مقدارinvalid credentials
را در قالب JSON برگردانید. در غیر اینصورت، یک آرایه شامل کلیدtoken
با مقدار توکن تولیدشده توسط Laravel Passport را در پاسخ برگردانید.
پنج route زیر از middleware auth:api
استفاده میکنند و نیازمند هدرهای Accept: application/json
و Authorization: Bearer token
هستند. این route ها به کنترلر API\GameController
متصل هستند و باید پیادهسازی شوند:
- لیست بازیهای کاربر (
GET /games
): بازیهایی که کاربر در آنها میزبان یا حریف دارد را در قالب JSON برگردانید. - ساخت بازی جدید (
POST /games/create
): فیلدopponent
باید در بدنهی درخواست موجود باشد. در صورتی که ورودی شرایط لازم را نداشتند، خطاهای پیشفرض Validator لاراول را در قالب JSON برگردانید. در صورتی که کاربری با نام کاربری واردشده وجود نداشت، آرایهای شامل کلیدerror
با مقدارopponent does not exist
را با کد پاسخ 404 برگردانید. اگر نام کاربری واردشده با نام کاربری کاربر فعلی یکسان بود، آرایهای شامل کلیدerror
با مقدارyou cannot play with yourself
را برگردانید. در غیر اینصورت، بازی را ایجاد کرده و آن را در پاسخ بهصورت JSON برگردانید. - مشاهدهی اطلاعات بازی (
GET /games/{id}
): در صورتی که بازیای با شناسهی واردشده وجود نداشت یا کاربر در آن میزبان یا حریف نبود، آرایهای شامل کلیدerror
با مقدارgame does not exist
را با کد پاسخ 404 برگردانید. در غیر اینصورت، آبجکت بازی را در پاسخ برگردانید. - تأیید درخواست بازی (
GET /games/accept/{id}
): در صورتی که بازیای با شناسهی واردشده وجود نداشت یا کاربر در آن میزبان یا حریف نبود، آرایهای شامل کلیدerror
با مقدارgame does not exist
را با کد پاسخ 404 برگردانید. اگر بازی در حال انجام بود، آرایهای شامل کلیدerror
با مقدارgame is already ongoing
را برگردانید. اگر درخواست بازی قبلاً رد شده بود، آرایهای شامل کلیدerror
با مقدارgame is already rejected
را برگردانید. اگر بازی خاتمه یافته بود، آرایهای شامل کلیدerror
با مقدارgame is already finished
را برگردانید. در غیر اینصورت، وضعیت بازی را بهongoing
تغییر داده و آرایهای شامل مقدارsuccess
را در قالب JSON برگردانید. اگر کاربر میزبان بازی بود، آرایهای شامل کلیدerror
با مقدارyou cannot accept your games
را برگردانید. - رد درخواست بازی (
GET /games/reject/{id}
): در صورتی که بازیای با شناسهی واردشده وجود نداشت یا کاربر در آن میزبان یا حریف نبود، آرایهای شامل کلیدerror
با مقدارgame does not exist
را با کد پاسخ 404 برگردانید. اگر بازی در حال انجام بود، آرایهای شامل کلیدerror
با مقدارgame is already ongoing
را برگردانید. اگر درخواست بازی قبلاً رد شده بود، آرایهای شامل کلیدerror
با مقدارgame is already rejected
را برگردانید. اگر بازی خاتمه یافته بود، آرایهای شامل کلیدerror
با مقدارgame is already finished
را برگردانید. در غیر اینصورت، وضعیت بازی را بهrejected
تغییر داده و آرایهای شامل مقدارsuccess
را در قالب JSON برگردانید. اگر کاربر میزبان بازی بود، آرایهای شامل کلیدerror
با مقدارyou cannot reject your games
را برگردانید. - انجام حرکت در بازی (
POST /games/move/{id}
): فیلدposition
باید با مقداری عددی و در بازهی 1 تا 9 در بدنهی درخواست موجود باشد. در صورتی که ورودی شرایط لازم را نداشتند، خطاهای پیشفرض Validator لاراول را در قالب JSON برگردانید. در صورتی که بازیای با شناسهی واردشده وجود نداشت یا کاربر در آن میزبان یا حریف نبود، آرایهای شامل کلیدerror
با مقدارgame does not exist
را با کد پاسخ 404 برگردانید. اگر درخواست بازی در انتظار تأیید حریف بود، آرایهای شامل کلیدerror
با مقدارgame is already pending
را برگردانید. اگر درخواست بازی قبلاً رد شده بود، آرایهای شامل کلیدerror
با مقدارgame is already rejected
را برگردانید. اگر بازی خاتمه یافته بود، آرایهای شامل کلیدerror
با مقدارgame is already finished
را برگردانید. اگر نوبت کاربر نبود، آرایهای شامل کلیدerror
با مقدارit is not your turn
را برگردانید (توجه کنید که همیشه حریف شروعکنندهی بازی است). اگر موقعیت حرکت در حال حاضر ثبت شده بود، آرایهای شامل کلیدerror
با مقدارcell is already full
را برگردانید. در غیر اینصورت، حرکت را ثبت کرده و آرایهای شامل مقدارsuccess
را در قالب JSON برگردانید. توجه کنید که پس از ثبت حرکت، باید بررسی کنید که آیا برندهی بازی (یا مساوی شدن بازی) میتواند تعیین شود یا خیر. در صورتی که این مورد قابل تشخیص بود، وضعیت بازی باید تغییر کند.
توجه: شما تنها مجاز به تغییر فایلهای موجود در پوشهی /app
هستید.
آنچه باید آپلود کنید
پس از اعمال تغییرات، کل پروژه به غیر از پوشهی vendor
را Zip کرده و آپلود کنید. نام فایل Zip اهمیتی ندارد.
ارسال پاسخ برای این سؤال