Steps to create our Crossword Puzzle App
Step 1: Create a React Native app by using this command:
npx create-expo-app CrosswordPuzzle
Step 2: Navigate to our project through this command:
cd CrosswordPuzzle
Project Structure:
The updated dependencies in package.json file will look like:
"dependencies": {
"react-native-paper": "4.9.2",
"@expo/vector-icons": "^13.0.0"
}
Example: Add the following code in CrosswordGrid.js and App.js.
Javascript
//CrosswordGrid.js import React, { useState, useEffect } from 'react' ; import { View, TextInput, StyleSheet, Text, Button } from 'react-native' ; let level = 0; const generateInitialGrid = (crosswordData) => { const initialGrid = Array(7).fill(0).map(() => Array(8).fill( 'X' )); crosswordData[level].forEach(({ answer, startx, starty, orientation }) => { let x = startx - 1; let y = starty - 1; for (let i = 0; i < answer.length; i++) { if (orientation === 'across' ) { initialGrid[y][x + i] = '' ; } else if (orientation === 'down' ) { initialGrid[y + i][x] = '' ; } } }); return initialGrid; }; const generateAnswerGrid = (crosswordData) => { const answerGrid = Array(7).fill(0).map(() => Array(8).fill( 'X' )); crosswordData[level].forEach(({ answer, startx, starty, orientation }) => { let x = startx - 1; let y = starty - 1; for (let i = 0; i < answer.length; i++) { if (orientation === 'across' ) { answerGrid[y][x + i] = answer[i]; } else if (orientation === 'down' ) { answerGrid[y + i][x] = answer[i]; } } }); return answerGrid; }; const CrosswordGrid = ({ crosswordData }) => { const [grid, setGrid] = useState(generateInitialGrid(crosswordData)); useEffect(() => { setGrid(generateInitialGrid(crosswordData)); }, [crosswordData]); const handleInputChange = (row, col, text) => { const newGrid = [...grid]; newGrid[row][col] = text.toUpperCase(); setGrid(newGrid); }; const handleGenerate = () => { level = (level + 1) % 2; setGrid(generateInitialGrid(crosswordData)); }; const handleVerify = () => { const answerGrid = generateAnswerGrid(crosswordData); const isCorrect = JSON.stringify(grid) === JSON.stringify(answerGrid); if (isCorrect) { alert( 'Congratulations! Your crossword is correct.' ); } else { alert( 'Incorrect. Please try again.' ); } }; const handleReset = () => { setGrid(generateInitialGrid(crosswordData)); }; const handleSolve = () => { const answerGrid = generateAnswerGrid(crosswordData); setGrid(answerGrid); }; const renderGrid = () => ( <View> {grid.map((row, rowIndex) => ( <View key={rowIndex} style={styles.row}> {row.map((cell, colIndex) => ( <View key={colIndex} style={styles.cellContainer}> {crosswordData[level].map((entry) => { const { startx, starty, position } = entry; if (rowIndex + 1 === starty && colIndex + 1 === startx) { return ( <Text key={`digit-${position}`} style={styles.smallDigit}> {position} </Text> ); } return null ; })} <TextInput style={[styles.cell, grid[rowIndex][colIndex] === 'X' ? styles.staticCell: null ]} value={cell} editable={grid[rowIndex][colIndex] !== 'X' } onChangeText={(text) => handleInputChange(rowIndex,colIndex, text) } maxLength={1} /> </View> ))} </View> ))} </View> ); const renderQuestions = () => { const questions = { across: [], down: [] }; crosswordData[level].forEach(({ hint, orientation, position }) => { const questionText = `${position}. ${hint}`; questions[orientation].push( <Text key={`question-${position}`} style={styles.questionText}> {questionText} </Text> ); }); return ( <View> <View style={styles.headingContainer}> <Text style={styles.headingText}>Across</Text> </View> <View style={styles.questionsContainer}> {questions.across.map((question, index) => ( <View key={`across-question-container-${index}`}> {question} </View> ))} </View> <View style={styles.headingContainer}> <Text style={styles.headingText}>Down</Text> </View> <View style={styles.questionsContainer}> {questions.down.map((question, index) => ( <View key={`down-question-container-${index}`}> {question} </View> ))} </View> </View> ); }; return ( <View style={styles.container}> {renderQuestions()} {renderGrid()} <View style={styles.buttonContainer}> <Button color={ '#228B22' } title= "Generate" onPress={handleGenerate} style={styles.button} /> <View style={styles.gap} /> <Button color={ '#228B22' } title= "Verify" onPress={handleVerify} style={styles.button} /> <View style={styles.gap} /> <Button color={ '#228B22' } title= "Reset" onPress={handleReset} style={styles.button} /> <View style={styles.gap} /> <Button color={ '#228B22' } title= "Solve" onPress={handleSolve} style={styles.button} /> </View> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' , alignItems: 'center' , }, row: { flexDirection: 'row' , }, cellContainer: { position: 'relative' , }, cell: { borderWidth: 1, margin: 1, borderColor: '#228B22' , width: 30, height: 30, textAlign: 'center' , }, staticCell: { borderColor: 'transparent' , color: 'white' , }, smallDigit: { position: 'absolute' , top: 2, left: 2, fontSize: 10, fontWeight: 'bold' , }, questionsContainer: { justifyContent: 'space-between' , marginBottom: 10, padding: 10, }, questionText: { fontSize: 16, fontStyle: 'italic' , }, headingContainer: { marginTop: 10, marginBottom: 5, }, headingText: { fontSize: 18, fontWeight: 'bold' , color: '#228B22' , textAlign: 'center' , }, buttonContainer: { flexDirection: 'row' , justifyContent: 'space-around' , marginTop: 20, marginHorizontal: 10, }, button: { flex: 1, // Ensure equal width for both buttons }, gap: { width: 10, // Adjust the width as needed for the desired gap }, }); export default CrosswordGrid |
Javascript
//App.js import React from "react" ; import { View, StyleSheet } from "react-native" ; import CrosswordGrid from "./CrosswordGrid" ; const App = () => { // levels can be added here in the crosswordData const crosswordData = [ [ { answer: "TIGER" , hint: "The powerful predator roams the jungle" , startx: 4, starty: 1, orientation: "down" , position: 1, }, { answer: "EAGLE" , hint: "A majestic bird known for its keen eyesight" , startx: 4, starty: 4, orientation: "across" , position: 2, }, { answer: "ITALIC" , hint: "It's a style of typeface characterized by slanted letters" , startx: 7, starty: 1, orientation: "down" , position: 3, }, { answer: "INFINITE" , hint: "It describes something boundless or limitless in extent or quantity" , startx: 1, starty: 2, orientation: "across" , position: 4, }, ], [ { answer: "QUIVER" , hint: "To shake or tremble slightly, often with rapid movements" , startx: 1, starty: 4, orientation: "across" , position: 1, }, { answer: "TWIRL" , hint: "To spin or rotate quickly" , startx: 3, starty: 2, orientation: "down" , position: 2, }, { answer: "GAZE" , hint: "To look steadily and intently at something, often implying concentration or contemplation" , startx: 5, starty: 1, orientation: "down" , position: 3, }, { answer: "FLUTE" , hint: "A musical instrument with a high-pitched sound" , startx: 2, starty: 6, orientation: "across" , position: 4, }, ], ]; return ( <View style={styles.container}> <CrosswordGrid crosswordData={crosswordData} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: "center" , alignItems: "center" , }, }); export default App; |
Step to run the application:
Step 1: Open the terminal and enter the following command to run the app
npx expo start
Step 2: Depending on your Operating System, type the following command.
- To run on Android:
npx react-native run-android
- To run on Ios:
npx react-native run-ios
Output:
Create a Crossword Puzzle Game using React-Native
Crossword Puzzle is a traditional word power game. The user needs to guess words based on the hints provided. So here, we will create a basic crossword puzzle app in React Native. The crossword puzzle app contains four buttons namely Generate, Verify, Reset and Solve. The Generate button will create a new crossword puzzle, the Verify button will check the correctness of the solved puzzle, the Reset button will empty all the fields entered in the puzzle and the Solve button will solve the puzzle.
Preview of the Final Output: Let us have a look at how the final application will look like.