You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native填字游戏棋盘实现方案咨询及优化建议

React Native填字游戏棋盘实现建议

先优化你的数据结构

你当前的position用(0,0)在JS里会被解析成表达式,建议改成数组[0,0];另外across/down用对象存储虽然可行,但后续遍历生成矩阵时不如数组方便,可以调整为数组结构:

const crosswordData = {
  across: [
    {
      id: 1,
      question: "test",
      answer: "test",
      position: [0, 0],
      length: 4,
    }
  ],
  down: []
};

放弃FlatList,用嵌套View/ScrollView实现棋盘

FlatList更适合线性长列表,填字游戏是二维结构,用嵌套的行+列View更直观,索引处理也简单:

1. 自动生成棋盘矩阵

不用手动维护矩阵,根据单词数据自动生成包含黑格(0)、白格(1)、起始格(2)的矩阵:

// 计算棋盘最大行列数
const calculateBoardSize = (data) => {
  let maxRow = 0;
  let maxCol = 0;
  [...data.across, ...data.down].forEach(word => {
    const [row, col] = word.position;
    // 从across/down判断单词方向
    if (data.across.includes(word)) {
      maxCol = Math.max(maxCol, col + word.length);
    } else {
      maxRow = Math.max(maxRow, row + word.length);
    }
  });
  return { rows: maxRow + 1, cols: maxCol + 1 };
};

// 生成初始矩阵并标记特殊格子
const generateBoardMatrix = (data) => {
  const { rows, cols } = calculateBoardSize(data);
  // 默认全白格
  const matrix = Array(rows).fill().map(() => Array(cols).fill(1));

  // 标记横向单词起始格
  data.across.forEach(word => {
    const [row, col] = word.position;
    matrix[row][col] = 2;
  });

  // 标记纵向单词起始格
  data.down.forEach(word => {
    const [row, col] = word.position;
    matrix[row][col] = 2;
  });

  // 手动标记黑格(示例:第2行第3列设为黑格)
  // if (matrix[2]?.[3] !== undefined) matrix[2][3] = 0;
  return matrix;
};

2. 渲染棋盘组件

用ScrollView包裹所有行,每行是一个横向View,内部渲染单个格子组件:

import React from 'react';
import { View, ScrollView, Text, StyleSheet } from 'react-native';

// 单个格子组件
const CrosswordCell = ({ type, number }) => {
  return (
    <View style={[
      styles.cell,
      type === 0 ? styles.blackCell : styles.whiteCell,
      type === 2 && styles.startCell
    ]}>
      {/* 显示起始格数字 */}
      {type === 2 && <Text style={styles.cellNumber}>{number}</Text>}
      {/* 这里可以添加输入框或答案文本 */}
    </View>
  );
};

// 棋盘主组件
const CrosswordBoard = ({ data }) => {
  const matrix = generateBoardMatrix(data);
  // 映射起始格对应的数字
  const startNumberMap = {};
  data.across.forEach(word => {
    const key = `${word.position[0]}-${word.position[1]}`;
    startNumberMap[key] = word.id;
  });
  data.down.forEach(word => {
    const key = `${word.position[0]}-${word.position[1]}`;
    // 同一格子如果是横竖起始,保留先出现的数字
    startNumberMap[key] = startNumberMap[key] || word.id;
  });

  return (
    <ScrollView contentContainerStyle={styles.boardWrapper}>
      {matrix.map((row, rowIdx) => (
        <View key={rowIdx} style={styles.row}>
          {row.map((cellType, colIdx) => (
            <CrosswordCell
              key={`${rowIdx}-${colIdx}`}
              type={cellType}
              number={startNumberMap[`${rowIdx}-${colIdx}`]}
            />
          ))}
        </View>
      ))}
    </ScrollView>
  );
};

// 样式定义
const styles = StyleSheet.create({
  boardWrapper: {
    padding: 12,
    alignItems: 'center',
  },
  row: {
    flexDirection: 'row',
  },
  cell: {
    width: 42,
    height: 42,
    borderWidth: 1,
    borderColor: '#222',
    justifyContent: 'flex-start',
    alignItems: 'flex-start',
    padding: 3,
  },
  blackCell: {
    backgroundColor: '#222',
  },
  whiteCell: {
    backgroundColor: '#fff',
  },
  startCell: {
    backgroundColor: '#f5f5f5',
  },
  cellNumber: {
    fontSize: 11,
    color: '#222',
  },
});

export default CrosswordBoard;

额外实用建议

  • 把格子的输入逻辑拆成独立组件(比如CellInput),负责处理用户输入、答案校验,避免棋盘组件逻辑臃肿。
  • 如果棋盘尺寸过大,可考虑用VirtualizedList实现行级虚拟化,但普通填字游戏用嵌套View性能足够。
  • 黑格信息可以单独维护一个坐标数组(比如blackCells: [[2,3], [4,1]]),生成矩阵时批量标记,更易维护。

内容的提问来源于stack exchange,提问作者A Drunken Turtle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 03:40:21