首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >填充一袋拼字砖

填充一袋拼字砖
EN

Code Review用户
提问于 2015-06-20 19:47:11
回答 5查看 1.5K关注 0票数 11

我正在装满一个装满拼字砖的袋子。在这些信件的袋子里应该有100个瓷砖:

代码语言:javascript
运行
复制
A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1 and Blanks-2.

这些数字/字母永远不应该改变。我有一个可行的解决方案,但这很可怕。有很多重复的代码,有很大的错误空间,而且可读性很差。我很难理解如何使这段代码更易读、更容易出错。有什么建议吗?如果有人知道更好的方法的话,我不反对把这门课划破。

Bag.cs

代码语言:javascript
运行
复制
public class Bag
{
    private Tile[] tiles = new Tile[100];
    private const int numA = 9;
    private const int numB = 2;
    private const int numC = 2;
    private const int numD = 4;
    private const int numE = 12;
    private const int numF = 2;
    private const int numG = 3;
    private const int numH = 2;
    private const int numI = 9;
    private const int numJ = 1;
    private const int numK = 1;
    private const int numL = 4;
    private const int numM = 2;
    private const int numN = 6;
    private const int numO = 8;
    private const int numP = 2;
    private const int numQ = 1;
    private const int numR = 6;
    private const int numS = 4;
    private const int numT = 6;
    private const int numU = 4;
    private const int numV = 2;
    private const int numW = 2;
    private const int numX = 1;
    private const int numY = 2;
    private const int numZ = 1;
    private const int numBlank = 2;

    public void populateTiles()
    {
        int i = 0;
        for (int j = 0; j < numA; j++)
        {
            tiles[i] = new Tile('A');
            i++;
        }
        for (int j = 0; j < numB; j++)
        {
            tiles[i] = new Tile('B');
            i++;
        }
        for (int j = 0; j < numC; j++)
        {
            tiles[i] = new Tile('C');
            i++;
        }
        for (int j = 0; j < numD; j++)
        {
            tiles[i] = new Tile('D');
            i++;
        }
        for (int j = 0; j < numE; j++)
        {
            tiles[i] = new Tile('E');
            i++;
        }
        for (int j = 0; j < numF; j++)
        {
            tiles[i] = new Tile('F');
            i++;
        }
        for (int j = 0; j < numG; j++)
        {
            tiles[i] = new Tile('G');
            i++;
        }
        for (int j = 0; j < numH; j++)
        {
            tiles[i] = new Tile('H');
            i++;
        }
        for (int j = 0; j < numI; j++)
        {
            tiles[i] = new Tile('I');
            i++;
        }
        for (int j = 0; j < numJ; j++)
        {
            tiles[i] = new Tile('J');
            i++;
        }
        for (int j = 0; j < numK; j++)
        {
            tiles[i] = new Tile('K');
            i++;
        }
        for (int j = 0; j < numL; j++)
        {
            tiles[i] = new Tile('L');
            i++;
        }
        for (int j = 0; j < numM; j++)
        {
            tiles[i] = new Tile('M');
            i++;
        }
        for (int j = 0; j < numN; j++)
        {
            tiles[i] = new Tile('N');
            i++;
        }
        for (int j = 0; j < numO; j++)
        {
            tiles[i] = new Tile('O');
            i++;
        }
        for (int j = 0; j < numP; j++)
        {
            tiles[i] = new Tile('P');
            i++;
        }
        for (int j = 0; j < numQ; j++)
        {
            tiles[i] = new Tile('Q');
            i++;
        }
        for (int j = 0; j < numR; j++)
        {
            tiles[i] = new Tile('R');
            i++;
        }
        for (int j = 0; j < numS; j++)
        {
            tiles[i] = new Tile('S');
            i++;
        }
        for (int j = 0; j < numT; j++)
        {
            tiles[i] = new Tile('T');
            i++;
        }
        for (int j = 0; j < numU; j++)
        {
            tiles[i] = new Tile('U');
            i++;
        }
        for (int j = 0; j < numV; j++)
        {
            tiles[i] = new Tile('V');
            i++;
        }
        for (int j = 0; j < numW; j++)
        {
            tiles[i] = new Tile('W');
            i++;
        }
        for (int j = 0; j < numX; j++)
        {
            tiles[i] = new Tile('X');
            i++;
        }
        for (int j = 0; j < numY; j++)
        {
            tiles[i] = new Tile('Y');
            i++;
        }
        for (int j = 0; j < numZ; j++)
        {
            tiles[i] = new Tile('Z');
            i++;
        }
        for (int j = 0; j < numBlank; j++)
        {
            tiles[i] = new Tile(' ');
            i++;
        }
    }
}

Tile.cs

代码语言:javascript
运行
复制
public class Tile
{
    private char letter;
    private int value;

    public Tile(char letter)
    {
        switch (letter)
        {
            case ' ':
                value = 0;
                break;
            case 'A':
            case 'E':
            case 'I':
            case 'O':
            case 'U':
            case 'L':
            case 'N':
            case 'S':
            case 'T':
            case 'R':
                value = 1;
                break;
            case 'D':
            case 'G':
                value = 2;
                break;
            case 'B':
            case 'C':
            case 'M':
            case 'P':
                value = 3;
                break;
            case 'F':
            case 'H':
            case 'V':
            case 'W':
            case 'Y':
                value = 4;
                break;
            case 'K':
                value = 5;
                break;
            case 'J':
            case 'X':
                value = 8;
                break;
            case 'Q':
            case 'Z':
                value = 10;
                break;
            default:
                Console.Error("Invalid Tile created!");
                break;
        }
    }
}
EN

回答 5

Code Review用户

回答已采纳

发布于 2015-06-20 20:52:17

抱歉,我只是想让事情变得更灵活,所以我必须更进一步.

我将在@EthanBierlein的版本和您的原始版本之间混合使用,并对其进行改进,进行以下更改:

  • 提取添加特定数量的瓷砖的方法
  • 能够在这里指定从瓷砖中得到的点。

在我看来,确实没有理由将某一字母的多少块配置分开,以及该瓷砖应该值多少个点。把它们都放在一个地方更合理,也更易于维护(考虑一下如果你想为其他语言拼字,不同的语言有不同的字母数量和不同的分数,更不用说不同的字母...了)

这将导致拼字游戏的设置更加可更改,您可以让A块具有不同的点值,您可以很容易地更改您在板中拥有的E块的数量,等等。您甚至可以扩展这个想法,并从配置文件中读取以确定每个方块应该有多少块。

我不是说你应该这么做,我只是说只要稍微修改一下代码,你就能做到这一点。

代码语言:javascript
运行
复制
using System.Collections.Generic;

class Bag
{
    public List<Tile> tiles = new List<Tile>();

    /// <summary>
    /// Populate the list tiles with scrabble tiles.
    /// </summary>
    public void PopulateTiles()
    {
        AddTile(9, 'A', 1);
        AddTile(2, 'B', 42);
        AddTile(2, 'C', 42);
        AddTile(4, 'D', 42);
        // ...
    }

    public void AddTile(int count, char letter, int score)
    {
        for (int i = 0; i < count; i++)
        {
            Tile tile = new Tile(letter, score); // Pass the score along to the tile as well
            tiles.Add(tile);
        }
    }
}

注意:方法名称应该使用PascalCase命名约定,而不是camelCase。从我的代码中可以看到,populateTiles应该是PopulateTiles

票数 13
EN

Code Review用户

发布于 2015-06-20 20:19:18

预警:我不是最有经验的C#程序员,所以如果有什么问题,只管提一下。

这里有太多无用的重复。这就需要使用System.Collections.Generic.Dictionary实现。您可以这样做来存储可能的瓷砖,以及它们的计数。

代码语言:javascript
运行
复制
public Dictionary<char, int> possibleTiles = new Dictionary<char, int>() {
    {'a', 9},
    {'b', 2},
    {'c', 2},
    ...
};

然后你可以像这样翻阅这本字典。您将使用键作为要添加到您的tiles数组中的块,并使用该值作为这些特定瓷砖的数量。

代码语言:javascript
运行
复制
foreach(KeyValuePair<char, int> item in possibleTiles)
{
    // Add item.key item.value times to the tiles array.
}

最后,作为参考,这里是my版本的Bag类。但是请注意,它使用的是List<Tile>而不是数组。

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;

/// <summary>
/// Represents a bag of scrabble tiles.
/// </summary>
class Bag
{
    public List<Tile> tiles = new List<Tile>();
    private Dictionary<char, int> possibleTiles = new Dictionary<char, int>() {
        {'a', 9}, {'b', 2}, {'c', 2}, {'d', 4}, {'e', 12},
        {'f', 2}, {'g', 3}, {'h', 2}, {'i', 9}, {'j', 1},
        {'k', 1}, {'l', 4}, {'m', 2}, {'n', 6}, {'o', 8},
        {'p', 2}, {'q', 1}, {'r', 6}, {'s', 4}, {'t', 6},
        {'u', 4}, {'v', 2}, {'w', 2}, {'x', 1}, {'y', 2},
        {'z', 1}, {' ', 2}
    };

    /// <summary>
    /// Populate the list tiles with scrabble tiles.
    /// </summary>
    public void PopulateTiles()
    {
        foreach(KeyValuePair<char, int> item in possibleTiles)
        {
            Tile tile = new Tile(item.Key);
            int amount = item.Value; 
            for(int n = 0; n <= amount; n++)
            {
                tiles.Add(tile);
            }
        }
    }
}
票数 13
EN

Code Review用户

发布于 2015-06-21 04:22:28

嗯,你似乎有很多重复:

代码语言:javascript
运行
复制
    for (int j = 0; j < numD; j++)
    {
        tiles[i] = new Tile('D');
        i++;
    }
    for (int j = 0; j < numE; j++)
    {
        tiles[i] = new Tile('E');
        i++;
    }

这两者之间有什么独特之处?为什么我们不能复制并粘贴它们呢?答案是numD\numE'D'\'E'

我们可以立即思考--想象一下,如果这些是值而不是硬编码的话?

代码语言:javascript
运行
复制
List<Tile> tiles = new List<Tile>(); //For simplicity.

public void AddTiles(char letter, int count)
{
    var newTiles = Enumerable.Range(0,count)
                   .Select(_ => new Tile(letter));
    tiles.AddRange(newTiles);
}

哇,太简单了!我们不必跟踪当前索引i、每个循环j的索引、需要添加多少块new Tile[100]或任何循环条件!

我们没有很好地跟踪这些值,所以让我们跟随西蒙·安德烈-福斯伯格的领导,并跟踪比分:

代码语言:javascript
运行
复制
public void AddTiles(char letter, int count, int score)
{
    var newTiles = Enumerable.Range(0,count)
                   .Select(_ => new Tile(letter, score));
    tiles.AddRange(newTiles);
}

哇!我们刚刚对程序的功能做了很大的修改,只需要添加一个参数!很简单吧?

不过,我还是不高兴。我们怎么打电话给AddTiles?是像这样吗?

代码语言:javascript
运行
复制
 public void PopulateTiles()
{
    AddTiles(9, 'A', 1);
    AddTiles(2, 'B', 3);
    AddTiles(2, 'C', 3);
    AddTiles(4, 'D', 2);
    // ...
}

我觉得不太对劲。它很长,很重复,而且很难编码--我们很难修改字典。如果我们有一个简单的方法来表示我们想要的瓷砖就好了?哦,等等,我们有!

A-9,B-2,C-2,D-4,E-12,F-2,G-3,H2,I-9,J-1,K-1,L-4,M-2,N-6,O-8,P2,Q-1,R-6,S-4,T-6,U-4,V-2,W-2,X-1,Y-2,Z-1和Blanks-2。

你已经有了一个简洁的方法来表达你的意图.那你为什么不用呢?为什么要重新发明轮子?

然而,我会做一些小的变化,以减少错误的风险,允许得分,并使‘空白’不那么神奇:

A:9:1,B:2:3,C:2:3,D:4:2,E:12:1,F:2:4,G:3:2,H:2:4,I:9:1,J:1:8,K:1:5,L:4:1,M:2:3,N:6:1,O:8:1,P:2:3,Q:1:10,R:6:1,S:4:1,T:6:1,U:4:1,V:2:4,W:2:4,X:1:8,Y:2:4,Z:1:10, :2:0

现在,这很容易修改和读取(尽管有了更多的时间/空间,我会使用换行符而不是,,或者json/csv来使阅读变得更干净)。

现在,我的程序看起来有点像这样:

代码语言:javascript
运行
复制
const string defaultAlphabet = "A:9:1,B:2:3,C:2:3,D:4:2,E:12:1,F:2:4,G:3:2,H:2:4,I:9:1,J:1:8,K:1:5,L:4:1,M:2:3,N:6:1,O:8:1,P:2:3,Q:1:10,R:6:1,S:4:1,T:6:1,U:4:1,V:2:4,W:2:4,X:1:8,Y:2:4,Z:1:10, :2:0"

List<Tile> tiles = new List<Tile>(); //For simplicity.

public void Populate(string alphabet = defaultAlphabet)
{
    foreach (var stringTile in alphabet.Split(','))
    {
        var parts = stringTile.Split(':');
        AddTiles(parts[0], int.Parse(parts[1]), int.Parse(parts[2]));
    }
}

public void AddTiles(string letter, int count, int score)
{
    var newTiles = Enumerable.Range(0,count)
                   .Select(_ => new Tile(letter, score));
    tiles.AddRange(newTiles);
}

注意我们现在的代码有多少?这很好--因为如果我们想改变应用程序的行为,我们只需要修改几行代码--我们就没有多余的地方需要担心了。然而,在不改变任何代码的情况下,我们可以彻底改变所使用的字母表--甚至可以使它的用户可以改变!

票数 8
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/94202

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档