انتخاب‌کننده تودرتو


ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

nested-selector
├── index.html
└── styles.css
Plain text
راه‌اندازی پروژه
  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • سپس فایل index.html را در مرورگر خود باز کنید.

جزئیات🔗

در فایل html داده شده دو تگ p در داخل یک div با ایدی container و یک تگ p دیگر بیرون از آن قرار گرقته است.

شما باید با استفاده از انتخاب‌کننده‌های مناسب استایلی بسازید که باعث شود تگ‌های داخل container دارای رنگ indigo و تگ خارج از آن دارای رنگ indianred باشد.

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل styles.css هستید.
  • فقط فایلی را که مجاز به تغییر هستید باید آپلود نمایید.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

مقدار یک ویژگی المان ممکن است چندین بار تغییر کند ولی هربار مقدار جدیدی بگیرد. برای مثال رنگ یک تگ p یکبار مشکی است و یکبار قرمز. درباره این موضوع یک سری قواعد وجود دارد که هرکدام اولویتی دارند و بسته به اولویت آن‌ها، استایل‌ها داده می‌شود.

یکی از این موارد قرار گرفتن استایل جدید بعد از استایل ما می‌باشد.

یکی دیگر از این موارد استفاده از !important در هنگام استایل‌دهی می‌باشد که صرف از نظر از تقدم استایل‌ها، آن استایل که دارای !important می‌باشد، انتخاب می‌شود.

درنهایت ترکیب اولویت‌ها و انتخاب‌کننده‌ها منجر به انتخاب استایل توسط مرورگر می‌شود.

راهنمایی ۲

مهم‌ترین و پرکاربردترین قواعد انتخاب استایل توسط مرورگر این است که هرچه انتخاب‌کننده (selector) خاص‌تر باشد، آن انتخاب می‌شود.

a {
  color: yellow;
}
nav > a {
  color: green;
}
Plain text

در مثال بالا رنگ تگ‌های a سبز انتخاب می‌شود چرا که انتخاب‌کننده خاص‌تر است.

ترکیب این قاعده با قاعده قبلی منجر به انتخاب استایل توسط مرورگر می‌شود.

راهنمایی۳

استایل‌های داخل HTML به استایل‌های داخل فایل‌های CSS مقدم هستند. این تقدم را می‌توان با استفاده از important! از بین برد. برای تغییر تقدم important! می‌توان سلکتور را مشخص‌تر کرد. در این حالت استایلی که سلکتور آن خاص‌تر باشد، انتخاب می‌شود.

محصولات


ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

products
├── assets
│   └── Vazir.ttf
├── cypress
│   ├── fixtures
│   │   └── example.json
│   ├── integration
│   │   └── sample.spec.js
│   ├── plugins
│   │   └── index.js
│   └── support
│       ├── commands.js
│       └── index.js
├── cypress.json
├── index.html
├── package-lock.json
├── package.json
├── script.js
└── styles.css
Plain text
راه‌اندازی پروژه
  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • سپس فایل index.html را در مرورگر خود باز کنید.

جزئیات🔗

در این سوال میخواهیم تغییراتی را در لیست داده شده ایجاد کنیم و لیست جدید را رندر کنیم. در پروژه اولیه در فایل script.js تابعی‌ با نام changeProducts وجود داره که کد شما در آن قسمت قرار میگیرد. شما باید در این تابع لیست جدیدی با تغییرات خواسته شده ایجاد کنید و تابع renderProducts را با لیست جدید صدا بزنید. تابع changeProducts وقتی صدا زده میشود که دکمه "اعمال تغییرات" کلیک شود. (کد این قسمت در پروژه اولیه وجود دارد)

تغییرات خواسته شده

  • قیمت‌ محصولات باید نصف شود.
  • تاریخ با استفاده از Date و متد toLocaleDateString فرمت شود. (راهنمایی: timestamp داده شده در فیلد date محصولات به صورت ثانیه است اما Date نیاز به میلی ثانیه دارد. این تبدیل باید انجام شود)

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل script.js هستید.
  • تعدادی تست نمونه در پروژه اولیه وجود دارد که با استفاده از آن‌ها می‌توانید کد خود را تست کنید.
  • فقط فایلی را که مجاز به تغییر هستید باید آپلود نمایید.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

با استفاده از map روی لیست محصولات داده شده میتوانید لیست جدید با تغییرات خواسته شده را ایجاد کنید.

راهنمایی ۲

تغییر خواسته شده برای تاریخ به این صورت است که ابتدا date را ضرب در ۱۰۰۰ میکنیم که به میلی ثانیه تبدیل شود بعد آن را به new Date میدهیم و متد toLocaleDateString رو آن صدا میزنیم.

راهنمایی۳

برای خواندن مطالب بیشتر در مورد map و Date میتوانید از این لینک‌ها استفاده کنید:

لینک برای مپ

لینک برای تاریخ

بازی XO


ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

tic-tac-toe
├── cypress
│   ├── fixtures
│   │   └── example.json
│   ├── integration
│   │   └── sample.spec.js
│   ├── plugins
│   │   └── index.js
│   └── support
│       ├── commands.js
│       └── index.js
├── cypress.json
├── index.html
├── package-lock.json
├── package.json
├── script.js
└── style.css
Plain text
راه‌اندازی پروژه
  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • سپس فایل index.html را در مرورگر خود باز کنید.

جزئیات🔗

این سوال یکی از تمرین‌‌های دوره فرانت‌اند و بخش سوم ساخت بازی XO است. تا این بخش کلیات بازی ساخته شده اما بازی هیچگاه برنده ندارد. در این بخش میخواهیم این قوانین را به بازی اضافه کنیم.

نکاتی که برای اضافه کردن عملکرد برد و باخت و مساوی به بازی باید به آن‌ها توجه کنید:

  • اگر سه سلول افقی یا عمودی یا قطری یکی باشند، بازی برنده دارد. اگر این سه سلول X باشند، این بازیکن برنده بازی است و در قسمت وضعیت بازی باید "Player X has won" نوشته شود و اگر O باشند، باید در قسمت وضعیت بازی "Player O has won" نوشته شود.
  • هرگاه بازی برنده داشت ادامه بازی ممکن نیست یعنی وقتی روی سلول‌های خالی کلیک شود، اتفاقی نیفتد (با X یا O پر نشود).
  • اگر بازی برنده نداشت و تمام سلول‌ها پر شدند، بازی مساوی است و داخل قسمت وضعیت بازی باید " Game ended in a draw" نوشته شود.

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل script.js هستید.
  • تعدادی تست نمونه در پروژه اولیه وجود دارد که با استفاده از آن‌ها می‌توانید کد خود را تست کنید.
  • فقط فایلی را که مجاز به تغییر هستید باید آپلود نمایید.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

با استفاده از gameState میتوانید تمام شدن بازی و برنده یا مساوی بودن بازی را مشخص کنید. اگر بازی برنده داشت بازی را متوقف کنید.

راهنمایی ۲

بعداز اینکه بازی برنده یا مساوی شد، gameActive باید false شود و موقع کلیک چک شود که اگر gameActive برابر false بود حرکت انجام نشود. gameActive بعداز کلیک شدن روی شروع دوباره true میشود.

راهنمایی ۳

برای تشخیص برد میتوانید یک آرایه به این صورت تعریف کنید: (لیست زیر کامل نیست و فقط شامل حالت‌های افقی برای برد است)

const winningConditions = [
  [0, 1, 2],
  [3, 4, 5],
  [6, 7, 8],
  ...
];
JavaScript

شامل تمام حالت‌های برد و با یک حلقه روی winningConditions اگر این سه تا نقطه در gameState برابر بودند، یعنی بازی برنده دارد.

Input Mask


مهارت‌های لازم:

  • آشنایی با state

ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

input-mask
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── __tests__
│   │   └── sample.test.js
│   ├── App.js
│   ├── Input.js
│   ├── cities.json
│   ├── index.css
│   └── index.js
├── package-lock.json
└── package.json
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید NodeJS و npm را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • در پوشه‌ی input-mask ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • پس از انجام موفق این مراحل، با مراجعه به آدرس http://localhost:3000/ می‌توانید نتیجه را ببینید.

جزئیات🔗

در این سوال شما باید:‌

  1. شهر ها را از فایل cities.json بخوانید
  2. کامپوننت Input را داخل div رندر کنید
  3. با استفاده از تابعی که به ‍‍handleChange اینپوت میدهید، اولین شهری که با حروف ورودی اینپوت شروع میشود را پیدا کنید و شهر پیدا شده را به hint اینپوت بدهید
  • اگر اینپوت خالی باشد، hint هم باید خالی شود
  • اگر شهری پیدا نشد hint باید خالی باشد
  • به حروف بزرگ و کوچک حساس است

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل App.js هستید.
  • تعدادی تست نمونه در پروژه اولیه وجود دارد که با استفاده از آن‌ها می‌توانید کد خود را تست کنید.
  • پس از اعمال تغییرات، پروژه را ZIP کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

در جاوااسکریپت تابعی وجود دارد به اسم startsWith که وظیفه‌اش چک کردن اینکه یک string با string دیگر شروع شده باشد.

"test".startsWith("te")  // true
JavaScript
راهنمایی ۲

برای hint از هوک useState استفاده کنید که در ابتدا یک رشته خالی "" است. وقتی شهر را پیدا کردید مقدارش را به مقدار آن شهر تغییر دهید و وفتی متن داخل اینپوت خالی شد مقدارش را به خالی "" تغییر دهید.

راهنمایی۳

مقدار اینپوت را میتوانید به وسیله تابعی که به کامپوننت Input میدهید بدست آورید. این تابعی که تعریف میکنید یک event میگیرد و با event.target.value میتوانید به مقدار اینپوت دسترسی پیدا کنید.

Auth Context


مهارت‌های لازم:

  • آشنایی با context
  • آشنایی با fetch
  • کار با فرم

ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

auth-context
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── __tests__
│   │   └── sample.test.js
│   ├── components
│   │   ├── login.js
│   │   └── register.js
│   ├── context
│   │   └── auth-context.js
│   ├── hacks
│   │   ├── hack-fetch.js
│   │   └── users.js
│   ├── app.js
│   ├── authenticated-app.js
│   ├── index.css
│   ├── index.js
│   └── unauthenticated-app.js
├── .env
├── package-lock.json
└── package.json
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید NodeJS و npm را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • در پوشه‌ی auth-context ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • پس از انجام موفق این مراحل، با مراجعه به آدرس http://localhost:3000/ می‌توانید نتیجه را ببینید.

جزئیات🔗

در این سوال شما باید در فایل auth-context.js کانتکس و provider بسازید که وظیفه آن به‌اشتراک‌گذاری کاربر و لاگین یا لاگ‌اوت بودن آن در تمام کامپوننت‌ها است. کامپوننت‌های login و register را طوری کامل کنید که هنگام submit فرم موجود، اطلاعات کاربر به صورت درخواست POST به آدرس سرور مورد نظر ارسال شود. اگر درخواست فرستاده شده موفقیت‌آمیز بود کاربر باید در کانتکست ثبت شود و اگر ایراد داشت باید هندل شود و ارور برگشت داده شده در div با کلاس error-message نشان داده شود.

آدرس سرور برای ثبت نام:

http://localhost:8989/api/register

آدرس سرور برای لاگین:

http://localhost:8989/api/login

برای دانستن بیشتر در مورد fetch می‌توانید از این لینک استفاده کنید:

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

نکات🔗

شما تنها مجاز به اعمال تغییر در فایل‌های زیر هستید:

src/context/auth-context.js

src/components/login.js

src/components/register.js

  • نیازی به تغییر یا دیدن فایل‌های موجود در پوشه hacks ندارید.
  • تعدادی تست نمونه در پروژه اولیه وجود دارد که با استفاده از آن‌ها می‌توانید کد خود را تست کنید.
  • پس از اعمال تغییرات، پروژه را ZIP کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

برای قسمت مقدار AuthProvider نیاز به ابجکت با سه تا فیلد: user که ابجکت کاربر، login تابعی که کاربر را ثبت میکند و و logout که کاربر را null قرار میدهد. هنگام ثبت‌نام و لاگین بعداز ارسال درخواست تابع login از این context صدا زده میشود.

راهنمایی ۲

در صفحات لاگین و ثبت‌نام هنگام submit فرم باید یک درخواست POST بوسیله fetch به آدرس گفته شده ارسال شود. داده ارسالی یک آبجکت شامل username و password است. این username و password را میتوانید به دو صورت بگیرید. اگر از onSubmit روی فرم استفاده میکنید میتوانید از event.target.elements بگیرید که برای مثال مقدار username به صورت event.target.elements.username.value است یا میتوانید از استیت استفاده کنید.

راهنمایی۳

نکته: مقدار value اینپوت‌ها داخل فرم‌ها را تغییر ندهید، نیازی به اینکار نیست و با value تست‌ها تداخل ایجاد میکند.

بازی مار


مهارت‌های لازم:

  • تسلط به hook
  • کار کاردن با state و reducer
  • آشنایی با قوانین بازی مار

ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

snake-game
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── __tests__
│   │   └── sample.test.js
│   ├── assets
│   │   └── index.css
│   ├── components
│   │   ├── apple.js
│   │   ├── game.js
│   │   └── snake.js
│   ├── hooks
│   │   └── use-snake.js
│   ├── index.js
│   ├── initialState.js
│   └── logic.js
├── package-lock.json
└── package.json
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید NodeJS و npm را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • در پوشه‌ی snake-game ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • پس از انجام موفق این مراحل، با مراجعه به آدرس http://localhost:3000/ می‌توانید نتیجه را ببینید.

جزئیات🔗

در این سوال شما باید هوک useSnake که در فایل hooks/use-snake.js تعریف شده را کامل کنید. این هوک در کامپوننت game.js استفاده شده و آبجکتی شامل تمام اعضای وضعیت اولیه بازی برمیگرداند که در ابتدا برابر با آن است و سپس براساس موارد زیر تغییر میکند. شما در این سوال باید تغییرات لازم را در هر ۱۰۰ میلی‌ثانیه (سرعت بازی) و کلیک شدن دکمه‌های w s a d در کیبورد روی وضعیت بازی اعمال کنید. (وضعیت اولیه بازی را حتما از فایل initialState.js بخوانید)

  • مار و غذا در ابتدا در مکان اولیه تعریف شده هستند.
  • در شروع کار مار به سمت راست شروع به حرکت میکند.
  • حرکت‌ها یک لیست است که در حالت اولیه یک آیتم دارد، با فشار دادن دکمه های w s a d اگر حرکت مخالف اولین حرکت تو این لیست نباشد به لیست اضافه میشود. وقتی حرکت‌ها داخل لیست بیشتر از یکی باشد به ترتیب از اولین حرکت، رفته و از لیست خارج میشوند تا به یک آیتم در لیست برسد. (مسیر حرکت مار اولین ایتم لیست حرکت‌ها است و این لیست همواره حداقل یک آیتم دارد)
  • مار بعد از خوردن غذا رشد میکند.
  • غذا بعد از خورده شدن تو مکان رندمی از بورد ظاهر میشود که حتما داخل بورد است.
  • بازی با خوردن مار با خودش دوباره از وضعیت اولیه شروع میشود.

وضعیت اولیه بازی

{
  cols: 20,
  rows: 14,
  board: {width: 700, height: 500},
  speed: 100,
  moves: [EAST],
  snake: [{x: 2, y: 2}],
  apple: {x: 16, y: 2},
}
JSON

مختصات

مختصات‌ها در بازی مار به صورت یه ابجکت هستند. مبدا مخصات {x: 0, y: 0} گوشه بالا سمت چپ بورد بازی است.

نمودار مربع ابی نشان داده شده در مختصات {x: 2, y: 1} است.

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل‌هایhooks/use-snake.js و logic.js هستید.
  • فایل logic.js فقط یک فایل اضافه است که بتوانید توابعی که مربوط به logic بازی است را در آن تعریف کنید. این فایل میتواند خالی باشد
  • تعدادی تست نمونه در پروژه اولیه وجود دارد که با استفاده از آن‌ها می‌توانید کد خود را تست کنید.
  • پس از اعمال تغییرات، پروژه را ZIP کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.

قسمت آموزشی🔗

در این قسمت راهنمایی‌های سوال، به مرور اضافه می‌شود. مشکلات‌تان در راستای حل سوال را می‌توانید از بخش "سوال بپرسید" مطرح کنید.

راهنمایی ۱

از useReducer برای مدیریت استیت بازی استفاده کنید و INIT_STATE را به عنوان استیت اولیه به آن بدهید.

راهنمایی ۲

بعداز تعریف useReducer از یک useEffect برای تعریف یک interval استفاده میکنیم که در هر ۱۰۰ میلی ثانیه dispatch را با یک اسمی مانند move صدا میزند این interval را در یک متغیر میذاریم تا هنگام return، بتوانیم clearInterval را روی آن صدا بزنیم.

از یک useEffect دیگر برای تعریف دکمه‌های w a s d استفاده میکنیم و dispatch را با اسمی مانند change_direction و البته جهت جدید صدا میزنیم.

بقیه برنامه، فقط منطق برنامه است که داخل reducer نوشته میشوند.

توجه: این فقط یکی از روش‌های ساخت این بازی است و قطعا روش‌های دیگری هم وجود دارد.

راهنمایی۳

قوانین بازی مار:

اگر head بعدی مار که قراره حرکت کنیم را nextHead در نظر بگیریم

  • برخورد:‌ برخورد وقتی اتفاق میفتد که مختصات nextHead با مختصات یکی از نقطه‌های مار برابر باشد.
  • حرکت مار: اگر مار برخورد داشت به حالت اولیه برمیگردد، اگر برخورد نداشت با اضافه کردن nextHead به نقطه‌های مار به جز آخرین نقطه بدست می‌آید اما در صورت خوردن سیب آخرین نقطه هم اضافه میشود.
  • سیب در یک نقطه رندوم یعنی x باید عدد صحیح رندوم بین ۰ و اندازه cols‌ (که از INIT_STATE میاد) و y باید عدد صحیح رندوم بین ۰ و rows (که از INIT_STATE میاد) باشد.