نیما در این روزهای کرونایی حوصلهاش به شدت سر رفته. از این رو، تصمیم گرفته است تا با کمک دوست صمیمیاش، محمدرضا، یک وبسایت ساده بسازد که در آن بتوان 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 اهمیتی ندارد.
ارسال پاسخ برای این سؤال