UVA_227 - Puzzle

本文深入探讨了游戏开发领域的核心技术,包括游戏引擎、动画、3D空间视频等,结合实际案例解析关键概念与实践方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


 Puzzle 

A children's puzzle that was popular 30 years ago consisted of a 5x5 framewhich contained 24 small squares of equal size. A unique letter of thealphabet was printed on each small square. Since there were only 24 squareswithin the frame, the framealso contained an empty position which was the same size as a small square.A square could be moved into that empty position if it were immediately tothe right, to the left, above, or below the empty position. The object of thepuzzle was to slide squares into the empty position so that the framedisplayed the letters in alphabetical order.

The illustration below represents a puzzle in its original configuration andin its configuration after the following sequence of 6 moves:

 
		 1) 		 The square above the empty position moves.

2) The square to the right of the empty position moves.

3) The square to the right of the empty position moves.

4) The square below the empty position moves.

5) The square below the empty position moves.

6) The square to the left of the empty position moves.

Write a program to display resulting frames given their initial configurationsand sequences of moves.

Input

Input for your program consists of several puzzles. Each is described by itsinitial configuration and the sequence of moves on the puzzle. The first 5lines of each puzzle description are the starting configuration. Subsequentlines give the sequence of moves.

The first line of the frame display corresponds to the top line of squaresin the puzzle. The other lines follow in order. The empty position in a frameis indicated by a blank. Each display line contains exactly 5 characters,beginning with the character on the leftmost square (or a blank ifthe leftmost square is actually the empty frame position). The display lineswill correspond to a legitimate puzzle.

The sequence of moves is represented by a sequence of As, Bs, Rs, and Ls todenote which square moves into the empty position. A denotes that the squareabove the empty position moves; B denotes that the square below the emptyposition moves; L denotes that the square to the left of the emptyposition moves; R denotes that the square to the right of the empty positionmoves. It is possible that there is an illegal move, even when it isrepresented by one of the 4 move characters. If an illegal move occurs, thepuzzle is considered to have no final configuration. This sequence of movesmay be spread over several lines, but it always ends in the digit 0. Theend of data is denoted by the character Z.

Output

Output for each puzzle begins with an appropriately labeled number(Puzzle #1, Puzzle #2, etc.). If the puzzle has no final configuration, thena message to that effect should follow. Otherwise that final configurationshould be displayed.

Format each line for a final configuration so that there is a single blankcharacter between two adjacent letters. Treat the empty square the sameas a letter. For example, if the blank is an interior position, then it willappear as a sequence of 3blanks - one to separate it from the square to the left, one for theempty position itself, and one to separate it from the square to the right.

Separate output from different puzzle records by one blank line.

Note:The first record of the sample input corresponds to the puzzle illustrated above.

Sample Input

TRGSJ
XDOKI
M VLN
WPABE
UQHCF
ARRBBL0
ABCDE
FGHIJ
KLMNO
PQRS 
TUVWX
AAA
LLLL0
ABCDE
FGHIJ
KLMNO
PQRS 
TUVWX
AAAAABBRRRLL0
Z

Sample Output

Puzzle #1:
T R G S J
X O K L I
M D V B N
W P   A E
U Q H C F

Puzzle #2:
  A B C D
F G H I E
K L M N J
P Q R S O
T U V W X

Puzzle #3:
This puzzle has no final configuration.

 

题意:

模拟题,给定一个5*5的字母矩阵,按照给定的指令,移动字母,成功输出最后指令即可,否则输出This puzzle has no final configuration.

解题思路:

1. 先读入矩阵,然后要把全部指令读入,进行模拟判定

2. 注意要用getline()读入每一行,因为可能会有空格,cin读入会分隔

错误分析:

1. 开始犯了一个错误,没有把全部指令读入,就去判断。比如说对于指令AAAAABBRRRLL0,其可以是

   AAAA

   ABBRR

   RL

   L

   0

   这种换行形式,所以一定要读到0为止,即把全部指令保存下来,再去判断

2. 要用cin.get()读一个enter产生的换行,因为回车键生成的换行符留存了输入队列中,后面的getline(cin,str)看到换行符后,将认为是一个空行。

3. Runtime error 最后一直有这个错误,后来发现调用strchr()函数产生的问题

 

代码如下:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
using namespace std;

char puzzle[10][10];
int r0,c0;//记录空格的位置
const char* turns = "ABLR";
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};

void read(int row, string str)
{
    for(int j=0;j<5;j++){
        puzzle[row][j] = str[j];
        if(str[j]==' ') { r0 = row; c0 = j;}
    }
}

bool move_p(char turn)
{
    int flag = 1;
    //int t = (strchr(turns,turn)-turns);
    int t;
    if(turn == 'A') t =0;
    else if(turn == 'B') t =1;
    else if(turn == 'L') t =2;
    else if(turn == 'R') t =3;
    int x,y;
    x = r0 + dx[t]; y = c0 + dy[t];
    if(x>=0&&x<=4&&y>=0&&y<=4){
        puzzle[r0][c0] = puzzle[x][y];
        puzzle[x][y] = ' ';
        r0 = x; c0 =y;
    }
    else flag = 0;
    if(flag) return true;
    else return false;
}

int main()
{
    //freopen("227.txt","r",stdin);
    string str,order;
    int icase = 0;
    while(1)
    {
        if(icase!=0) cin.get();
        getline(cin,str); //cin>>str;
        if(str[0]=='Z') break;
        if(icase!=0) cout<<endl;//不同样例之间换行
        read(0,str);
        for(int i=1;i<=4;i++)
        {
            getline(cin,str);
            read(i,str);
        }
        int ok,len;
        order.clear();
        //读入全部指令
        while(1)
        {
            string temp; cin>>temp;
            order += temp;
            len = temp.length();
            if(temp[len-1]=='0') break;
            else continue;
        }

        ok = 1;len = order.length();
        for(int i=0;i<len-1;i++)
        {
            if(move_p(order[i])) continue;
            else { ok = 0; break;}
        }
        cout<<"Puzzle #"<<++icase<<":"<<endl;
        if(ok)
        {
            int i,j;
            for(i=0;i<5;i++){
                for(j=0;j<4;j++) cout<<puzzle[i][j]<<" ";
                cout<<puzzle[i][j]<<endl;
            }
            //cout<<endl;
        }
        else cout<<"This puzzle has no final configuration."<<endl;
    }
    return 0;
}

    

 

<think>根据错误信息,`generateDefaultGrid` 函数在 `GameWindow` 类中未声明。我们需要在头文件中声明该函数,并在源文件中定义它。此外,在 `generatePuzzle` 函数中调用 `generateDefaultGrid` 之前,确保它已经被声明。 修改步骤: 1. 在 `gamewindow.h` 的 `private` 部分添加 `generateDefaultGrid` 函数的声明。 2. 在 `gamewindow.cpp` 中实现 `generateDefaultGrid` 函数。 3. 确保在 `generatePuzzle` 中调用 `generateDefaultGrid` 时,该函数已经被定义(即顺序问题),或者将 `generateDefaultGrid` 的定义放在 `generatePuzzle` 之前。 但是,为了避免顺序问题,我们可以将 `generateDefaultGrid` 的定义放在 `generatePuzzle` 之前。或者,我们可以保持函数定义顺序不变,但在 `generatePuzzle` 中调用之前,在源文件顶部添加函数的前向声明(在类外部)。然而,由于 `generateDefaultGrid` 是成员函数,必须在类中声明。 因此,我们修改头文件: 在 `gamewindow.h` 的 `private` 部分添加: ```cpp void generateDefaultGrid(); ``` 然后在 `gamewindow.cpp` 中实现该函数。 另外,注意错误信息中显示在 `generatePuzzle` 中调用 `generateDefaultGrid` 时,编译器认为该函数未声明。这是因为在 `gamewindow.cpp` 中,`generatePuzzle` 的定义在 `generateDefaultGrid` 的定义之前,而编译器从上到下编译,所以不知道后面有 `generateDefaultGrid` 的定义。因此,我们可以在 `gamewindow.cpp` 中,将 `generateDefaultGrid` 的定义移到 `generatePuzzle` 之前,或者在 `generatePuzzle` 之前声明该函数(在类外部的前向声明不适用于成员函数)。所以,我们只能调整函数定义的顺序。 但是,由于我们在头文件中已经声明了该函数,所以只要在 `gamewindow.cpp` 中实现该函数,无论顺序如何,在 `generatePuzzle` 中调用都是可以的。因为成员函数的声明在头文件中,在 `generatePuzzle` 中调用时,编译器已经知道该函数的存在。 然而,错误信息显示在 `generatePuzzle` 中调用时,编译器说“在此作用域中尚未声明”,这是因为在头文件中我们还没有添加这个函数的声明。 所以,主要问题是在头文件中没有声明 `generateDefaultGrid` 函数。我们首先在头文件中声明它。 修改后的 `gamewindow.h` 片段: ```cpp class GameWindow : public QMainWindow { // ... 其他代码 ... private: // ... 其他成员函数声明 ... void generateDefaultGrid(); // 添加这一行 // ... 其他成员变量 ... }; ``` 然后在 `gamewindow.cpp` 中实现这个函数,放在任何位置都可以(但为了清晰,可以放在 `generatePuzzle` 之后,但需要确保在调用之前有声明,而声明已经在头文件中)。 另外,注意错误信息中还有一个问题:在 `generatePuzzle` 中调用 `generateDefaultGrid` 时,编译器没有找到它。这是因为我们之前没有在类中声明,现在添加声明后应该可以解决。 修改后的 `gamewindow.cpp` 中 `generateDefaultGrid` 的实现: 我们实现一个简单的默认网格,例如放置一些预定义的单词。 注意:在 `generateDefaultGrid` 中,我们需要初始化网格并放置一些单词,同时更新 `m_grid` 和 `m_solution`。 实现示例: ```cpp void GameWindow::generateDefaultGrid() { // 简单默认网格,确保显示 QStringList defaultWords = { "HELLO", "WORLD", "CROSS", "WORDS", "PUZZL" // 注意:这里应该是5个字母,但"PUZZLE"有6个字母,所以改为"PUZZL" }; // 重新初始化网格 m_grid = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_solution = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_cellToWordMap = QVector<QVector<int>>(GRID_SIZE, QVector<int>(GRID_SIZE, -1)); m_wordRecords.clear(); // 放置单词(垂直放置,每列一个单词) for (int i = 0; i < GRID_SIZE; i++) { if (i < defaultWords.size()) { placeWord(0, i, defaultWords[i], true); // 水平放置,每行一个单词 } } // 填充剩余的空格为随机字母 for (int row = 0; row < GRID_SIZE; ++row) { for (int col = 0; col < GRID_SIZE; ++col) { if (m_grid[row][col].isNull()) { m_grid[row][col] = getRandomLetter(); m_solution[row][col] = m_grid[row][col]; } } } } ``` 注意:上面的默认网格是水平放置5个单词,每行一个单词。这样确保网格被填满。 但是,我们还需要注意,在 `generatePuzzle` 函数中,如果多次尝试失败,就会调用 `generateDefaultGrid`。 另外,在 `generatePuzzle` 函数中,我们添加了 `m_isGenerating = true;` 和 `m_isGenerating = false;`,以避免在生成过程中更新UI。 现在,我们修改 `gamewindow.cpp` 中的 `generatePuzzle` 函数,确保在调用 `generateDefaultGrid` 后,也像正常生成一样显示初始提示并更新UI。 但是,在 `generateDefaultGrid` 中,我们已经生成了网格,所以在 `generatePuzzle` 中调用它之后,我们还需要更新UI。这部分逻辑已经在 `generatePuzzle` 的后面部分(显示初始提示和更新UI)处理了。 因此,我们只需要确保在 `generateDefaultGrid` 中正确生成了网格,然后 `generatePuzzle` 后面的UI更新代码会执行。 最后,编译错误应该解决。 但是,我们还需要注意,在 `generateDefaultGrid` 中,我们调用了 `placeWord` 来放置单词,所以 `placeWord` 函数应该能够正常工作。 如果还有问题,请检查 `placeWord` 函数是否能够处理水平放置的单词(即 `horizontal=true` 的情况)。 由于我们修改了头文件,需要重新运行qmake并重新编译。 修改后的完整 `gamewindow.h` 和 `gamewindow.cpp` 如下(只显示修改部分): 在 `gamewindow.h` 中: ```cpp private: // ... 已有函数声明 ... void generateDefaultGrid(); // 添加这行 ``` 在 `gamewindow.cpp` 中: ```cpp void GameWindow::generateDefaultGrid() { // 简单默认网格,确保显示 QStringList defaultWords = { "HELLO", "WORLD", "CROSS", "WORDS", "PUZZL" // 注意:5个字母 }; // 重新初始化网格 m_grid = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_solution = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_cellToWordMap = QVector<QVector<int>>(GRID_SIZE, QVector<int>(GRID_SIZE, -1)); m_wordRecords.clear(); // 放置单词(水平放置,每行一个单词) for (int row = 0; row < GRID_SIZE; row++) { if (row < defaultWords.size()) { placeWord(row, 0, defaultWords[row], true); // 从第0列开始,水平放置 } } // 填充剩余的空格为随机字母 for (int row = 0; row < GRID_SIZE; ++row) { for (int col = 0; col < GRID_SIZE; ++col) { if (m_solution[row][col].isNull()) { m_solution[row][col] = getRandomLetter(); m_grid[row][col] = m_solution[row][col]; } } } } ``` 注意:在 `placeWord` 调用中,我们使用 `true` 表示水平放置。另外,我们放置了5个单词,每行一个。 这样修改后,应该可以编译通过,并且当生成失败时使用默认网格。 如果仍然遇到编译错误,请检查是否在 `gamewindow.cpp` 中实现了 `generateDefaultGrid` 函数,并且头文件中已经声明。 最后,重新运行构建命令。</think>您的构建错误是由于 `generateDefaultGrid()` 函数在头文件中未声明导致的。让我们修复这个问题并优化代码: ### 解决方案: #### 1. 在头文件中声明 `generateDefaultGrid()` 函数 ```cpp // gamewindow.h #ifndef GAMEWINDOW_H #define GAMEWINDOW_H // ... 其他代码保持不变 ... private: // ... 其他成员函数声明 ... void generateDefaultGrid(); // 添加这行声明 // ... 其他成员变量 ... }; #endif // GAMEWINDOW_H ``` #### 2. 实现 `generateDefaultGrid()` 函数 ```cpp // gamewindow.cpp void GameWindow::generateDefaultGrid() { // 简单默认网格,确保显示 QStringList defaultWords = { "HELLO", "WORLD", "CROSS", "WORDS", "PUZZL" // 注意:5个字母 }; // 重新初始化网格 m_grid = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_solution = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_cellToWordMap = QVector<QVector<int>>(GRID_SIZE, QVector<int>(GRID_SIZE, -1)); m_wordRecords.clear(); // 放置单词(水平放置) for (int row = 0; row < GRID_SIZE; row++) { if (row < defaultWords.size()) { placeWord(row, 0, defaultWords[row], true); } } // 填充剩余的空格 for (int row = 0; row < GRID_SIZE; ++row) { for (int col = 0; col < GRID_SIZE; ++col) { if (m_solution[row][col].isNull()) { m_solution[row][col] = getRandomLetter(); m_grid[row][col] = m_solution[row][col]; } } } } ``` #### 3. 修复 `generatePuzzle()` 函数 ```cpp void GameWindow::generatePuzzle() { m_isGenerating = true; const int maxRetry = 10; bool valid = false; for (int i = 0; i < maxRetry; ++i) { generateWithFixedPattern(); if (validateGrid()) { valid = true; break; } } if (!valid) { qWarning() << "无法生成有效字谜,使用默认网格"; generateDefaultGrid(); // 使用后备方案 } // 更新UI显示 for (int row = 0; row < GRID_SIZE; ++row) { for (int col = 0; col < GRID_SIZE; ++col) { m_cells[row][col]->setText(QString(m_grid[row][col])); m_cells[row][col]->setEnabled(true); } } // 显示初始提示(30%的单元格) int revealCount = GRID_SIZE * GRID_SIZE * 0.3; for (int i = 0; i < revealCount; i++) { int r = getRandomIndex(GRID_SIZE); int c = getRandomIndex(GRID_SIZE); m_cells[r][c]->setStyleSheet("background: #aaffaa;"); } m_isGenerating = false; } ``` #### 4. 修复 `generateWithFixedPattern()` 函数 ```cpp void GameWindow::generateWithFixedPattern() { // 1. 正确初始化网格 m_grid = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_solution = QVector<QVector<QChar>>(GRID_SIZE, QVector<QChar>(GRID_SIZE, QChar())); m_cellToWordMap = QVector<QVector<int>>(GRID_SIZE, QVector<int>(GRID_SIZE, -1)); m_wordRecords.clear(); // 2. 预设单词列表 QStringList centerColWords = {"WORDS", "LOGIC", "IDEAS", "BRAIN"}; QStringList col0Words = {"BLOCK", "CHAIN", "FRAME", "PHASE"}; QStringList col4Words = {"DREAM", "FAITH", "HOPE", "PEACE"}; // 3. 确保有有效单词 if (centerColWords.isEmpty()) centerColWords << "WORDS"; if (col0Words.isEmpty()) col0Words << "BLOCK"; if (col4Words.isEmpty()) col4Words << "DREAM"; // 4. 随机选择单词 QString centerColWord = centerColWords.at(getRandomIndex(centerColWords.size())); QString col0Word = col0Words.at(getRandomIndex(col0Words.size())); QString col4Word = col4Words.at(getRandomIndex(col4Words.size())); // 5. 放置垂直单词 - 修复位置 placeWord(0, 1, centerColWord, false); // 第1列(索引1) placeWord(0, 0, col0Word, false); // 第0列 placeWord(0, 4, col4Word, false); // 第4列 // 6. 填充水平单词 for (int row = 0; row < GRID_SIZE; ++row) { // 跳过已填充的行 if (!m_solution[row][0].isNull() && !m_solution[row][1].isNull() && !m_solution[row][2].isNull() && !m_solution[row][3].isNull() && !m_solution[row][4].isNull()) { continue; } // 尝试放置水平单词 QVector<QPair<int, QChar>> conditions; for (int col = 0; col < GRID_SIZE; col++) { if (!m_solution[row][col].isNull()) { conditions.append(qMakePair(col, m_solution[row][col])); } } QVector<QString> candidates = findWords(5, conditions); if (!candidates.isEmpty()) { QString word = candidates.at(getRandomIndex(candidates.size())); placeWord(row, 0, word, true); } else { // 填充随机字母 for (int col = 0; col < GRID_SIZE; col++) { if (m_solution[row][col].isNull()) { m_solution[row][col] = getRandomLetter(); m_grid[row][col] = m_solution[row][col]; } } } } } ``` ### 关键修复说明: 1. **函数声明问题**: - 在头文件中添加了 `generateDefaultGrid()` 声明 - 在源文件中实现了该函数作为后备方案 2. **网格初始化优化**: - 简化了网格初始化逻辑 - 确保所有单元格都有值 3. **单词放置逻辑**: - 修复了垂直单词的位置参数 - 优化了水平单词放置逻辑 - 添加了后备机制(随机字母填充) 4. **验证逻辑简化**: - 移除了复杂的验证逻辑 - 使用简单的网格完整性检查 5. **UI更新优化**: - 简化了初始提示显示 - 确保所有单元格都正确显示 ### 完整构建流程: ```bash # 清理旧构建 rm -rf build mkdir build cd build # 生成Makefile qmake ../CrosswordGame.pro # 编译项目 make -j$(nproc) # 运行程序 ./CrosswordGame ``` ### 相关问题:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值