Stroop效应的改组算法

问题描述 投票:-1回答:4

我正在研究一个小型的C# Winforms应用程序,它复制了几个关于认知心理学的视觉实验。我试图以编程方式创建它们来训练我的技能,而不是使用预制图像。

现在我正在研究Stroop Effect,我正在尝试重现以下图像:

Example

我准备了两个不同的数组,一个包含颜色,另一个包含颜色名称:

Color[] colors =
{
    Color.Blue,
    Color.Red,
    Color.Black,
    Color.Green
};

String[] names =
{
    "BLUE",
    "RED",
    "BLACK",
    "GREEN"
};

第一步很简单。我所要做的就是使用各自的ForegroundColor绘制字符串,这样names[0]将使用colors[0]打印,names[1]将使用colors[1]打印,依此类推......

这是艰巨的任务。一旦字符串数组被洗牌:

Random r = new Random();
String[] namesRandom = names.OrderBy(x => r.Next()).ToArray();   

我也要把colors阵列洗牌。但必须确保没有颜色与其正确的名称相匹配。所以,例如,这是正确的:

"BLACK" Color.Green
"GREEN" Color.Red
"RED"   Color.Blue
"BLUE"  Color.Black

这将是错误的:

"BLACK" Color.Black -> Matching Color/Name
"GREEN" Color.Red
"RED"   Color.Blue
"BLUE"  Color.Green

有关如何有效实现这一目标的任何想法?我想避免使用shuffle until condition is met方法。

附: =在Bitmap上绘制字符串不是问题,我在这个开发任务上不需要帮助。

[编辑]

对于因为无法将shuffle until condition is met的概念与几行代码相关联的10k-ers,或者因为他们认为我在玩俄罗斯方块时想要完成我的工作,这里是我当前算法的快速实现:

public class Program
{
    private static Random s_Random = new Random();

    public static void Main(String[] args)
    {
        Color[] colors =
        {
            Color.Blue,
            Color.Red,
            Color.Black,
            Color.Green
        };

        String[] names =
        {
            "BLUE",
            "RED",
            "BLACK",
            "GREEN"
        };

        while (MatchingPairs(colors, names)) 
        {
            colors = Shuffle(colors);
            names = Shuffle(names);
        }

        for (Int32 i = 0; i < colors.Length; ++i)
            Console.WriteLine(colors[i].Name.ToUpperInvariant() + " | " + names[i]);
    }

    private static Boolean MatchingPairs(Color[] colors, String[] names)
    {
        for (Int32 i = 0; i < colors.Length; ++i)
        {
            if (colors[i].Name.ToUpperInvariant() == names[i])
                return true;
        }

        return false;
    }

    private static T[] Shuffle<T>(T[] array)
    {
        return array.OrderBy(x => s_Random.Next()).ToArray();
    }
}

所以,正如你所看到的,我可以用手指键入代码。我只是想知道是否有更好的方法来获得相同的结果。

c# .net algorithm
4个回答
1
投票

这可能不是最好的方法,但它应该工作正常。解决这个问题的一种方法是分配随机名称,直到你只剩下两个(where index i == Count - 2)。此时,如果索引i + 1中的项目名称是其余选项之一,请将其用于索引i中的项目。

这里有一些使用控制台应用程序(和ConsoleColor)的示例代码,但概念是相同的。我使用了一个结合了ConsoleColorstring的类,所以如果你想使用数组,它需要一些修改。

第一课:

class NamedColor
{
    public ConsoleColor Color { get; set; }
    public string Name { get; set; }
    public NamedColor(ConsoleColor color, string name)
    {
        Color = color;
        Name = name;
    }
}

以及将这些对象的列表打印到控制台的方法:

static void PrintColors(IEnumerable<NamedColor> colors)
{
    Console.BackgroundColor = ConsoleColor.Gray;
    Console.Write(new string(' ', 80));

    foreach (var color in colors)
    {
        Console.ForegroundColor = color.Color;
        Console.Write(color.Name + " ");
    }

    Console.Write(new string(' ', 139)); // Ugly, hard-coded length for simplicity
}

然后我们可以创建一个方法来获取这些对象的列表,将它们之间的所有名称混合,然后返回该新列表:

static NamedColor[] ShuffleNames(NamedColor[] colors)
{
    var names = colors.Select(c => c.Name).ToList();
    var shuffled = new NamedColor[colors.Length];

    for (int i = 0; i < colors.Length; i++)
    {
        string name;

        // If there are only two items left, and our list of names contains 
        // the *next* item's name, then we must take that name for this item
        if (i == colors.Length - 2 && names.Contains(colors[i + 1].Name))
        {
            name = colors[i + 1].Name;
        }
        else
        {
            // Choose a random name from all names except this item's name
            var candidateNames = names.Where(n => !n.Equals(colors[i].Name)).ToList();
            name = candidateNames[rnd.Next(candidateNames.Count)];
        }

        shuffled[i] = new NamedColor(colors[i].Color, name);
        names.Remove(name);
    }

    return shuffled;
}

然后我们可以随机播放列表,然后将名称洗牌,然后打印出如下列表:

private static Random rnd = new Random();

static void Main(string[] args)
{
    var correctColors = new NamedColor[]
    {
        new NamedColor(ConsoleColor.Blue, "BLUE"),
        new NamedColor(ConsoleColor.Black, "BLACK"),
        new NamedColor(ConsoleColor.Red, "RED"),
        new NamedColor(ConsoleColor.Green, "GREEN"),
    };

    PrintColors(correctColors);

    for (int count = 0; count < 10; count++)
    {
        // Shuffle the items, then shuffle the names
        var shuffledColors = correctColors.OrderBy(c => rnd.NextDouble()).ToArray();
        shuffledColors = ShuffleNames(shuffledColors);

        PrintColors(shuffledColors);
    }

    Console.ResetColor();
    Console.WriteLine("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

产量

enter image description here


1
投票

您可以执行以下操作:

  1. 为每个名称实施有效颜色规则: Func<string, IEnumerable<Color>> validColorsRule = s => { switch (s) { case "BLUE": return colors.Except(new[] { Color.Blue }); case "RED": return colors.Except(new[] { Color.Red }); case "BLACK": return colors.Except(new[] { Color.Black }); case "GREEN": return colors.Except(new[] { Color.Green }); default: throw new NotSupportedException(); } };
  2. Color构建洗牌的Enumerable.Aggregate数组: Color[] colorRandom = namesRandom.Aggregate(Enumerable.Empty<Color>(), (acc, n) => acc.Concat(new[] { validColorsRule(n).Except(acc) .OrderBy(x => r.Next()) .FirstOrDefault() })) .ToArray();

1
投票

您可以将其重新表述为伪随机问题。

  1. 生成一个介于1和n-1之间的随机整数(比如i)并移动颜色数组(使用它的副本)
  2. 现在生成0和n-1之间的随机序列而不进行替换,并打印名称和颜色
static void Main(string[] args)
{
            ConsoleColor[] colors =
       {
            ConsoleColor.Blue,
            ConsoleColor.Red,
            ConsoleColor.Black,
            ConsoleColor.Green
        };

            String[] names =
            {
            "BLUE",
            "RED",
            "BLACK",
            "GREEN"
        };

            Random r = new Random();
            int i = 0;
            while(i==0)
                i=r.Next() % (names.Length-1);
            List<int> rndList = Enumerable.Range(0,names.Length).OrderBy(x => r.Next()).ToList();
            Console.BackgroundColor = ConsoleColor.White;
            foreach(int j in rndList)
            {
                int k = (j+i) % (colors.Length);
                Console.ForegroundColor = colors[k];
                Console.Write(names[j] + " ");
            }
}

1
投票

我认为你正试图创造一个随机的紊乱。对此进行网络搜索可以找到一篇关于在http://epubs.siam.org/doi/pdf/10.1137/1.9781611972986.7上有效生成此类内容的论文 - 由Martinez,Panholzer和Prodinger创作的“Generating Random Disrangements”。然而,本文还表明,即使n可能非常大,随机选择的排列是一个紊乱的机会仍然非常接近1 / e,所以简单的解决方案就是生成一个随机排列并检查它是否是一种紊乱,重复直到这是真的,在实践中可能足以满足大多数目的。

© www.soinside.com 2019 - 2024. All rights reserved.