当前位置: 首页 > ops >正文

wordle game(猜词游戏)小demo【react + ts】

wordle game(猜词游戏)小demo。

绿色代表字母对位置对,黄色代表字母对位置错,灰色是都错。

源码地址

play~

preview

#1 - init

#2 - using json-server

创建db.json文件,录入需要mock的json数据。

npm install json-server
json-server ./data/db.json [--port 3001]

#3 - Making a Wordle Hook

import { useState } from 'react'type LetterColor = 'green' | 'yellow' | 'grey'type LetterObject = {key: stringcolor: LetterColor
}type UseWordleReturn = {turn: numbercurrentGuess: stringguesses: LetterObject[][]isCorrect: booleanhandleKeyup: (event: KeyboardEvent) => void
}const useWordle = (solution: string): UseWordleReturn => {const [turn, setTurn] = useState<number>(0)const [currentGuess, setCurrentGuess] = useState<string>('')const [guesses, setGuesses] = useState<LetterObject[][]>([])const [history, setHistory] = useState<string[]>([])const [isCorrect, setIsCorrect] = useState<boolean>(false)// format a guess into an array of letter objects // e.g. [{key: 'a', color: 'yellow'}]const formatGuess = (): LetterObject[] => {// TODO: 实现格式化逻辑return []}// add a new guess to the guesses state// update the isCorrect state if the guess is correct// add one to the turn stateconst addNewGuess = () => {// TODO: 实现添加新猜测逻辑}// handle keyup event & track current guess// if user presses enter, add the new guessconst handleKeyup = ({key} : KeyboardEvent) => {// todo:处理按键响应}return { turn, currentGuess, guesses, isCorrect, handleKeyup }
}export default useWordle

#4 - Tracking the Current Guess

  // handle keyup event & track current guess// if user presses enter, add the new guessconst handleKeyup = ({key} : KeyboardEvent) => {console.log('key pressed - ' + key)if (key === 'Backspace') {setCurrentGuess((prev) => prev.slice(0, -1))return}if (/^[A-Za-z]$/.test(key)) {// 如果按下的是字母键,则添加到currentGuessif (currentGuess.length < 5) {setCurrentGuess((prev) => prev + key.toLowerCase())}}}

#5 - Submitting Guesses

const handleKeyup = ({key} : KeyboardEvent) => {// console.log('key pressed - ' + key)if (key === 'Enter') {if (turn >= 6) {console.log('You have used all your guesses.')return}if (currentGuess.length !== 5) {console.log('Current guess must be 5 characters long.')return}if (history.includes(currentGuess)) {console.log('You have already guessed that word.')return}const formatted = formatGuess()console.log('formatted guess: ', formatted)}if (key === 'Backspace') {setCurrentGuess((prev) => prev.slice(0, -1))return}if (/^[A-Za-z]$/.test(key)) {// 如果按下的是字母键,则添加到currentGuessif (currentGuess.length < 5) {setCurrentGuess((prev) => prev + key.toLowerCase())}}}

#6 - Checking & Formatting Guesses

  const formatGuess = (): LetterObject[] => {// console.log('formatting guess for ' + currentGuess)let solutionArray : (string | null)[] = [...solution]const formattedGuess: LetterObject[] = currentGuess.split('').map((letter) => {return { key: letter, color: 'grey' }})// find all green lettersformattedGuess.forEach((letterObject, index) => {if (letterObject.key === solutionArray[index]) {letterObject.color = 'green'solutionArray[index] = null // remove from solutionArray so we don't match it again}})// find all yellow lettersformattedGuess.forEach((letterObject) => {if (letterObject.color === 'green') return // skip already matched lettersconst letterIndex = solutionArray.indexOf(letterObject.key)if (letterIndex > -1) {letterObject.color = 'yellow'solutionArray[letterIndex] = null // remove from solutionArray so we don't match it again}})return formattedGuess}

#7 - Adding New Guesses

  // add a new guess to the guesses state// update the isCorrect state if the guess is correct// add one to the turn stateconst addNewGuess = (formattedGuess: LetterObject[]) => {if (currentGuess === solution) {setIsCorrect(true)} // console.log('adding new guess: ', formattedGuess)setGuesses(prevGuesses => [...prevGuesses,formattedGuess])setHistory(prevHistory => [...prevHistory,currentGuess])setCurrentGuess('')setTurn(prevTurn => prevTurn + 1)}

#8 - Creating a Game Grid

import { Row } from "./Row"
import type { LetterObject } from "../hooks/useWordle" // Adjust the path if neededtype GridProps = {guesses: LetterObject[][]currentGuess: stringturn: number
}const Grid = ({guesses, currentGuess, turn} : GridProps) => {return (<div className="grid">{guesses.map((guess, index) => {return <Row key={index}></Row>})}</div>)
}export default Grid
export const Row = () => {return (<div className="row"><div></div><div></div><div></div><div></div><div></div><div></div></div>)
}

#9 - Showing Past Guesses

import type { LetterObject } from "../hooks/useWordle"type RowProps = {guess?: LetterObject[]
}export const Row = ({ guess }: RowProps) => {if (guess) {return (<div className="row">{guess.map((letter, index) => {return <div key={index} className={letter.color}>{letter.key}</div>})}</div>)}return (<div className="row"><div></div><div></div><div></div><div></div><div></div></div>)
}

#10 - Showing the Current Guess

import type { LetterObject } from "../hooks/useWordle"type RowProps = {guess?: LetterObject[]currentGuess?: string
}export const Row = ({ guess, currentGuess }: RowProps) => {...if (currentGuess) {let letters = currentGuess.split('')return (<div className="row current">{letters.map((letter, index) => {return <div key={index} className="current">{letter}</div>})}{/* Fill the rest of the row with empty divs */}{Array.from({ length: 5 - letters.length }).map((_, index) => (<div key={index}></div>))}</div>)}...
}

#11 - Animating Tiles

.row > div.green {--background: #5ac85a;--border-color: #5ac85a;animation: flip 0.5s ease forwards;
}
.row > div.grey {--background: #a1a1a1;--border-color: #a1a1a1;animation: flip 0.6s ease forwards;
}
.row > div.yellow {--background: #e2cc68;--border-color: #e2cc68;animation: flip 0.5s ease forwards;
}
.row > div:nth-child(2) {animation-delay: 0.2s;
}
.row > div:nth-child(3) {animation-delay: 0.4s;
}
.row > div:nth-child(4) {animation-delay: 0.6s;
}
.row > div:nth-child(5) {animation-delay: 0.8s;
}
.row.current > div.filled {animation: bounce 0.2s ease-in-out forwards;
}/* keyframe animations */
@keyframes flip {0% {transform: rotateX(0);background: #fff;border-color: #333;}45% {transform: rotateX(90deg);background: white;border-color: #333;}55% {transform: rotateX(90deg);background: var(--background);border-color: var(--border-color);}100% {transform: rotateX(0deg);background: var(--background);border-color: var(--border-color);color: #eee;}
}@keyframes bounce {0% { transform: scale(1);border-color: #ddd;}50% { transform: scale(1.2);}100% {transform: scale(1);border-color: #333;}
}

#12 - Making a Keypad

import { useEffect, useState } from "react";export const Keypad = () => {const [letters, setLetters] = useState<string[]>([]);useEffect(() => {const fetchLetters = async () => {const response = await fetch("/mock/db.json");const data = await response.json();setLetters(data.letters.map((letter: { key: string }) => letter.key));};fetchLetters();}, []);return (<div className="keypad">{letters &&letters.map((letter, index) => <div key={index}>{letter}</div>)}</div>);
};

#13 - Coloring Used Keys

import { useEffect, useState } from "react";
import type { LetterColor } from "../hooks/useWordle";type KeypadProps = {usedKeys: { [key: string]: LetterColor }; // to track used keys and their colors
};export const Keypad = ({ usedKeys }: KeypadProps) => {...return (<div className="keypad">{letters &&letters.map((letter, index) => {const color = usedKeys[letter];return (<div key={index} className={color}>{letter}</div>);})}</div>);
};

#14 - Ending A Game

...export default function Wordle({ solution }: { solution: string }) {const { currentGuess, handleKeyup, guesses, isCorrect, turn, usedKeys } =useWordle(solution);useEffect(() => {window.addEventListener("keyup", handleKeyup);if (isCorrect) {console.log("Congratulations! You've guessed the word!");window.removeEventListener("keyup", handleKeyup);}if (turn >= 6 && !isCorrect) {console.log("Game over! The correct word was: " + solution);window.removeEventListener("keyup", handleKeyup);}return () => {window.removeEventListener("keyup", handleKeyup);};}, [handleKeyup]);...
}

#15 - Making a Modal

import React from 'react'type ModalProps = {isCorrect: booleansolution: stringturn: number
}const Modal = ({ isCorrect, solution, turn }: ModalProps) => {return (<div className='modal'>{isCorrect ? (<div><h2>Congratulations!</h2><p>You guessed the word "{solution}" in {turn + 1} turns!</p></div>) : (<div><h2>Game Over</h2><p>The correct word was "{solution}". Better luck next time!</p></div>)}<button onClick={() => window.location.reload()}>Play Again</button></div>)
}export default Modal
http://www.xdnf.cn/news/15884.html

相关文章:

  • 删除 XML 格式中双引号内的空格
  • 前后端分离项目进阶1---后端
  • Apache IoTDB(2):时序数据库 IoTDB 集群安装部署的技术优势与适用场景分析
  • Electron 主进程与渲染进程之间交互方式
  • 跑腿小程序|基于微信小程序的跑腿平台小程序设计与实现(源码+数据库+文档)
  • kotlin和Jetpack Compose对于Android系统来说是什么关系?
  • 【HTTP缓存机制深度解析:从ETag到实践策略】
  • c语言 进阶 动态内存管理
  • 客流分析核心算法 trajectory_event_analyzer数据结构
  • 深入解析Hadoop YARN:三层调度模型与资源管理机制
  • 单表查询-counter的使用
  • Centos卷挂载失败系统无法启动
  • c++ duiLib 使用xml文件编写界面布局
  • Protein FID:AI蛋白质结构生成模型评估新指标
  • axios二次封装-单个、特定的实例的拦截器、所有实例的拦截器。
  • Apache基础配置
  • C语言:深入理解指针(2)
  • 《汇编语言:基于X86处理器》第8章 复习题和练习,编程练习
  • Spring Cloud Gateway高危隐患
  • MySQL—表设计和聚合函数以及正则表达式
  • 2024年全国青少年信息素养大赛Scratch算法创意实践挑战赛 小高组 初赛 真题
  • Python适配器模式详解:让不兼容的接口协同工作
  • 【LeetCode数据结构】单链表的应用——环形链表问题详解
  • 详解Mysql索引合并
  • LeetCode 3202.找出有效子序列的最大长度 II:取模性质(动态规划)
  • lvs调度算法(10种)
  • TCL --- 列表_part1
  • 基于FPGA实现ARINC818
  • RocketMQ核心编程模型
  • 自动找客户软件有那些?