Scrabble

要解决的问题
在 Scrabble 游戏中,玩家通过拼出单词获得分数。一个单词的总分等于该单词中每个字母分值之和。
| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 3 | 3 | 2 | 1 | 4 | 2 | 4 | 1 | 8 | 5 | 1 | 3 | 1 | 1 | 3 | 10 | 1 | 1 | 1 | 1 | 4 | 4 | 8 | 4 | 10 |
例如,如果我们要计算单词 “CODE” 的分数,可以看到 ‘C’ 值 3 分,‘O’ 值 1 分,‘D’ 值 2 分,‘E’ 值 1 分。相加后,“CODE” 总共值 7 分。
请在名为 scrabble 的文件夹中创建 scrabble.c 文件,并用 C 实现一个程序,判断一局简短的类 Scrabble 游戏谁获胜。程序应提示输入两次:一次让 “Player 1” 输入单词,一次让 “Player 2” 输入单词。然后根据哪位玩家得分更高,输出 “Player 1 wins!”、“Player 2 wins!” 或者在双方得分相同时输出 “Tie!”。
演示
建议和提示
先写一些你确定能编译的代码
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
}
注意,你现在已经包含了一些头文件,这些头文件会让你能使用一些可能帮助你解决本题的函数。
在继续写更多代码前,先写一些伪代码
如果你还不确定如何解决这个问题,可以先把它拆成几个你大概能解决的小问题。例如,这个问题其实只包含少数几个步骤:
- 提示用户输入两个单词
- 计算每个单词的分数
- 输出获胜者
我们可以把这些步骤写成注释形式的伪代码,提醒自己要完成什么:
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Prompt the user for two words
// Compute the score of each word
// Print the winner
}
问题集中的某些题目,比如这一题,可能会包含“剧透式”提示(例如下面的提示),最终带你走完整个解法。虽然你可以使用这些代码,但我们强烈建议你先自己尝试。问题集中的其他题通常不会有这种完整演练;通常包含“完整剧透”的题目只是后面更大问题的热身版本。
把伪代码转换成代码
首先,思考如何提示用户输入两个单词。回忆一下,CS50 库中的 get_string 函数可以提示用户输入字符串。
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
// Print the winner
}
接下来,思考如何计算每个单词的分数。由于两个单词使用同样的计分算法,这正是进行抽象的好机会。这里我们定义一个名为 compute_score 的函数,它接受一个名为 word 的字符串作为输入,并以 int 形式返回该单词的分数。
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int compute_score(string word);
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// Print the winner
}
int compute_score(string word)
{
// Compute and return score for word
}
现在转向实现 compute_score。要计算一个单词的分数,你需要知道单词中每个字母对应的分值。可以用一个数组把字母和分值关联起来。想象一个包含 26 个 int 的数组,名为 POINTS,其中第一个数字是 ‘A’ 的分值,第二个数字是 ‘B’ 的分值,依此类推。把这个数组声明并初始化在任意单个函数之外,就可以确保包括 compute_score 在内的所有函数都能访问它。
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};
int compute_score(string word);
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// Print the winner
}
int compute_score(string word)
{
// Compute and return score for word
}
实现 compute_score 时,可以先尝试找出 word 中单个字母的分值。
- 记住,要找出字符串
s中第 n 个索引处的字符,可以写s[n]。例如,word[0]会给出word的第一个字符。 - 另外,记住计算机会使用 ASCII 表示字符;ASCII 是一种把每个字符表示为数字的标准。
- 还要记住,
POINTS的第 0 个索引POINTS[0]给出的是 ‘A’ 的分值。思考一下,如何把 ‘A’ 的数字表示转换成它对应分值的索引。那么 ‘a’ 呢?你需要对大写和小写字母应用不同的转换,所以isupper和islower这些函数可能会有帮助。 - 请记住,不是字母的字符应计为 0 分。例如,
!值 0 分。
如果你能正确计算 word 中一个字符的分值,那么很可能就能用循环把其他字符的分值加起来。自己尝试过上面的思路后,可以看看下面这个(相当直接的!)提示。
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};
int compute_score(string word);
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// Print the winner
}
int compute_score(string word)
{
// Keep track of score
int score = 0;
// Compute score for each character
for (int i = 0, len = strlen(word); i < len; i++)
{
if (isupper(word[i]))
{
score += POINTS[word[i] - 'A'];
}
else if (islower(word[i]))
{
score += POINTS[word[i] - 'a'];
}
}
return score;
}
最后,完成伪代码的最后一步:打印获胜者。记住,if 语句可以用来检查某个条件是否为真,而继续使用 else if 或 else 可以检查其他互斥的条件。
if (/* Player 1 wins */)
{
// ...
}
else if (/* Player 2 wins */)
{
// ...
}
else
{
// ...
}
尝试过上面的内容后,可以看看下面的提示(或者说,完整解法!)。
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Points assigned to each letter of the alphabet
int POINTS[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};
int compute_score(string word);
int main(void)
{
// Prompt the user for two words
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Compute the score of each word
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// Print the winner
if (score1 > score2)
{
printf("Player 1 wins!\n");
}
else if (score1 < score2)
{
printf("Player 2 wins!\n");
}
else
{
printf("Tie!\n");
}
}
int compute_score(string word)
{
// Keep track of score
int score = 0;
// Compute score for each character
for (int i = 0, len = strlen(word); i < len; i++)
{
if (isupper(word[i]))
{
score += POINTS[word[i] - 'A'];
}
else if (islower(word[i]))
{
score += POINTS[word[i] - 'a'];
}
}
return score;
}
如何测试
你的程序应当表现得像下面的示例一样。
$ ./scrabble
Player 1: Question?
Player 2: Question!
Tie!
$ ./scrabble
Player 1: red
Player 2: wheelbarrow
Player 2 wins!
$ ./scrabble
Player 1: COMPUTER
Player 2: science
Player 1 wins!
$ ./scrabble
Player 1: Scrabble
Player 2: wiNNeR
Player 1 wins!
正确性
check50 cs50/problems/2026/x/scrabble
代码风格
style50 scrabble.c
如何提交
在终端中执行以下命令提交你的作业,并按提示完成操作。
submit50 cs50/problems/2026/x/scrabble