用 AppleScript 编写的圣诞灯颜色唯一随机模式的算法
an algorithm for uniquely random patterns of colors for Christmas lights written in AppleScript
这 post 最终是关于为智能圣诞灯创建随机模式文件。
我选择了 7 种颜色(红色、绿色、蓝色、橙色、紫色、白色、深色),我想对其进行半随机化处理。
我有 4 个“框架”,它是一个 5 宽 x 4 高的网格,我想用“随机”颜色填充,没有颜色在我这边,或者直接上下并没有颜色在每个网格位置的帧之间重复。
以下是完全随机帧的示例。完全随机很容易,这就是我要寻找的“无重复”随机数。同样,这些框架不是我最终要寻找的,但它们很接近。此外,以下内容仅供视觉参考,在 AppleScript(或可能任何其他编程语言)中,以下将是列表列表。
P G O R D D O G D O P W D O G W O G B W
W B P D O P G R G B R G B O P D R B P G
R G B D O R O G O W P O W D R O G R W D
B G W D B D R G P R R W D O B B O G D W
所以这里有一些代码可以让我进入第一帧的第一列:
set colorList to {"R", "G", "B", "D", "O", "W", "P"}
set newColumn to {{}, {}, {}, {}, {}}
set previousColor to {}
set previousColumn to {}
repeat with i from 1 to 4 -- for the 4 frames that I need
repeat with j from 1 to 5 -- for the 5 columns that each frame needs
repeat with k from 1 to 4 -- for the 4 values I need in each column
set isRandom to false
set theColor to some item of colorList
if i is not greater than 1 then -- if i is 1 then it is the first frame of the series
if j is not greater than 1 then -- if J is 1 then it is the first column
if k is not greater than 1 then -- if K is 1 then its the first value of the column
set end of (item j of newColumn) to theColor
else
if theColor is not previousColor then -- if k is greater than 1 then ¬
--check the color against the previous color, to make sure they are not the same
set end of (item j of newColumn) to theColor
set previousColor to theColor
else
repeat until isRandom is true
set theColor to some item of colorList
if theColor is not previousColor then
set end of (item j of newColumn) to theColor
set isRandom to true
end if
end repeat
end if
end if
end if
end if
end repeat
end repeat
end repeat
我曾尝试更进一步,但每次我这样做时,它都会变成一团乱七八糟的 if-then-else 语句,让我迷失其中。
因此脚本在向列添加颜色之前需要做 3 件事:
- 确保列之前的颜色不一样
- 确保(如果我们正在处理的列不是第 1 列)颜色与前面的列项目不同,
- 确保(如果我们正在处理的帧超出第一帧)颜色与之前帧相同位置的颜色不同。
所以我要问的问题是,他们的处理程序或算法是否是我所缺少的(我不是 CS 专业的)可以使这项任务更直接?
这就是您可能需要了解的有关我的问题的全部信息,但为了参考起见,我正在尝试为圣诞灯创建图案。我脚本中的 colorList
实际上是这样的:
set colorList to {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}, {255, 128, 0}, {255, 255, 0},{0, 0, 0}}
所以最后我需要一个格式完全像这样的文本文件:
255, 0, 0
0, 0, 255
0, 0, 0
255, 255, 0
(每行前有一个space字符)
我获取文本文件,将其转换为二进制文件,然后使用一些 Python 将文件发送到灯正在使用的 REST API。
这些灯来自一家名为 Twinkly 的公司。
我只是想让我更轻松地创建一些场景(并希望在此过程中学到一些东西)。
好的,我继续在没有 objC 的情况下完成了这个。我使用的方法是首先构建一个适当大小和形状的空数组,然后 运行 通过数组添加颜色,阻止颜色被添加到更远的相邻单元格。它有一些棘手的方面——通过递归向下钻取嵌套列表,使用引用进行速度优化和列表处理,模拟一个版本的 indexPath 来定位列表元素——但你应该很快就能理解它。
我把剧本的定稿留给了你;这会生成 属性 fullList
中的文本元素列表,您可以将其转换为所需的形式。有什么问题可以在评论里提问。
property colorList : {"Red", "Green", "Blue", "Orange", "Purple", "White", "Dark"}
property fullList : missing value
property columns : 5
property rows : 4
property blocks : 4
my buildEmptyNestedList()
my setColorsRecursivelyInNestedList:(a reference to fullList) withIndexList:{}
return get fullList
on buildEmptyNestedList()
set fullList to {}
set fullListRef to a reference to fullList
repeat blocks times
set blocksList to {}
repeat rows times
set rowsList to {}
repeat columns times
set end of rowsList to {}
end repeat
copy rowsList to end of blocksList
end repeat
copy blocksList to end of fullListRef
end repeat
end buildEmptyNestedList
on setColorsRecursivelyInNestedList:nestedListElement withIndexList:idxList
local idx
if lists of nestedListElement is equal to {} then -- bottom level: empty list or list of strings
set localColors to my filterColorsByList:nestedListElement
set chosenColor to some item of localColors
set excludePathsList to my processPathList:idxList
repeat with aPathList in excludePathsList
set target to (my getSublistByIndexes:aPathList)
copy chosenColor to end of target
end repeat
set contents of nestedListElement to chosenColor
else
set idx to 1
repeat with aSublist in nestedListElement
copy idxList to nextIdxList
set nextIdxList to nextIdxList & idx
(my setColorsRecursivelyInNestedList:(a reference to (item idx of nestedListElement)) withIndexList:nextIdxList)
set idx to idx + 1
end repeat
end if
end setColorsRecursivelyInNestedList:withIndexList:
on getSublistByIndexes:idxList
set foundList to item (item 1 of idxList) of fullList
repeat with idx in (rest of idxList)
set foundList to item idx of foundList
end repeat
return foundList
end getSublistByIndexes:
on getElementFromList:aNestedList byIndexes:idxArray
set currIdx to item 1 of idxArray
if (count of idxArray) = 1 then
return item currIdx of aNestedList
else
return my getElementFromList:(item currIdx of aNestedList) byIndexes:(rest of idxArray)
end if
end getElementFromList:byIndexes:
on processPathList:aPathList
set pathCheckList to {}
repeat with i from 1 to count of aPathList
copy aPathList to tempList
set item i of tempList to (item i of tempList) + 1
if item i of tempList ≤ item i of {blocks, rows, columns} then
copy tempList to end of pathCheckList
end if
end repeat
return pathCheckList
end processPathList:
on filterColorsByList:aList
set filteredList to {}
set colorListRef to a reference to colorList
repeat with aColor in colorListRef
if aColor is not in aList then
copy aColor as text to end of filteredList
end if
end repeat
return filteredList
end filterColorsByList:
这 post 最终是关于为智能圣诞灯创建随机模式文件。
我选择了 7 种颜色(红色、绿色、蓝色、橙色、紫色、白色、深色),我想对其进行半随机化处理。
我有 4 个“框架”,它是一个 5 宽 x 4 高的网格,我想用“随机”颜色填充,没有颜色在我这边,或者直接上下并没有颜色在每个网格位置的帧之间重复。
以下是完全随机帧的示例。完全随机很容易,这就是我要寻找的“无重复”随机数。同样,这些框架不是我最终要寻找的,但它们很接近。此外,以下内容仅供视觉参考,在 AppleScript(或可能任何其他编程语言)中,以下将是列表列表。
P G O R D D O G D O P W D O G W O G B W
W B P D O P G R G B R G B O P D R B P G
R G B D O R O G O W P O W D R O G R W D
B G W D B D R G P R R W D O B B O G D W
所以这里有一些代码可以让我进入第一帧的第一列:
set colorList to {"R", "G", "B", "D", "O", "W", "P"}
set newColumn to {{}, {}, {}, {}, {}}
set previousColor to {}
set previousColumn to {}
repeat with i from 1 to 4 -- for the 4 frames that I need
repeat with j from 1 to 5 -- for the 5 columns that each frame needs
repeat with k from 1 to 4 -- for the 4 values I need in each column
set isRandom to false
set theColor to some item of colorList
if i is not greater than 1 then -- if i is 1 then it is the first frame of the series
if j is not greater than 1 then -- if J is 1 then it is the first column
if k is not greater than 1 then -- if K is 1 then its the first value of the column
set end of (item j of newColumn) to theColor
else
if theColor is not previousColor then -- if k is greater than 1 then ¬
--check the color against the previous color, to make sure they are not the same
set end of (item j of newColumn) to theColor
set previousColor to theColor
else
repeat until isRandom is true
set theColor to some item of colorList
if theColor is not previousColor then
set end of (item j of newColumn) to theColor
set isRandom to true
end if
end repeat
end if
end if
end if
end if
end repeat
end repeat
end repeat
我曾尝试更进一步,但每次我这样做时,它都会变成一团乱七八糟的 if-then-else 语句,让我迷失其中。
因此脚本在向列添加颜色之前需要做 3 件事:
- 确保列之前的颜色不一样
- 确保(如果我们正在处理的列不是第 1 列)颜色与前面的列项目不同,
- 确保(如果我们正在处理的帧超出第一帧)颜色与之前帧相同位置的颜色不同。
所以我要问的问题是,他们的处理程序或算法是否是我所缺少的(我不是 CS 专业的)可以使这项任务更直接?
这就是您可能需要了解的有关我的问题的全部信息,但为了参考起见,我正在尝试为圣诞灯创建图案。我脚本中的 colorList
实际上是这样的:
set colorList to {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 255}, {255, 128, 0}, {255, 255, 0},{0, 0, 0}}
所以最后我需要一个格式完全像这样的文本文件:
255, 0, 0
0, 0, 255
0, 0, 0
255, 255, 0
(每行前有一个space字符)
我获取文本文件,将其转换为二进制文件,然后使用一些 Python 将文件发送到灯正在使用的 REST API。 这些灯来自一家名为 Twinkly 的公司。 我只是想让我更轻松地创建一些场景(并希望在此过程中学到一些东西)。
好的,我继续在没有 objC 的情况下完成了这个。我使用的方法是首先构建一个适当大小和形状的空数组,然后 运行 通过数组添加颜色,阻止颜色被添加到更远的相邻单元格。它有一些棘手的方面——通过递归向下钻取嵌套列表,使用引用进行速度优化和列表处理,模拟一个版本的 indexPath 来定位列表元素——但你应该很快就能理解它。
我把剧本的定稿留给了你;这会生成 属性 fullList
中的文本元素列表,您可以将其转换为所需的形式。有什么问题可以在评论里提问。
property colorList : {"Red", "Green", "Blue", "Orange", "Purple", "White", "Dark"}
property fullList : missing value
property columns : 5
property rows : 4
property blocks : 4
my buildEmptyNestedList()
my setColorsRecursivelyInNestedList:(a reference to fullList) withIndexList:{}
return get fullList
on buildEmptyNestedList()
set fullList to {}
set fullListRef to a reference to fullList
repeat blocks times
set blocksList to {}
repeat rows times
set rowsList to {}
repeat columns times
set end of rowsList to {}
end repeat
copy rowsList to end of blocksList
end repeat
copy blocksList to end of fullListRef
end repeat
end buildEmptyNestedList
on setColorsRecursivelyInNestedList:nestedListElement withIndexList:idxList
local idx
if lists of nestedListElement is equal to {} then -- bottom level: empty list or list of strings
set localColors to my filterColorsByList:nestedListElement
set chosenColor to some item of localColors
set excludePathsList to my processPathList:idxList
repeat with aPathList in excludePathsList
set target to (my getSublistByIndexes:aPathList)
copy chosenColor to end of target
end repeat
set contents of nestedListElement to chosenColor
else
set idx to 1
repeat with aSublist in nestedListElement
copy idxList to nextIdxList
set nextIdxList to nextIdxList & idx
(my setColorsRecursivelyInNestedList:(a reference to (item idx of nestedListElement)) withIndexList:nextIdxList)
set idx to idx + 1
end repeat
end if
end setColorsRecursivelyInNestedList:withIndexList:
on getSublistByIndexes:idxList
set foundList to item (item 1 of idxList) of fullList
repeat with idx in (rest of idxList)
set foundList to item idx of foundList
end repeat
return foundList
end getSublistByIndexes:
on getElementFromList:aNestedList byIndexes:idxArray
set currIdx to item 1 of idxArray
if (count of idxArray) = 1 then
return item currIdx of aNestedList
else
return my getElementFromList:(item currIdx of aNestedList) byIndexes:(rest of idxArray)
end if
end getElementFromList:byIndexes:
on processPathList:aPathList
set pathCheckList to {}
repeat with i from 1 to count of aPathList
copy aPathList to tempList
set item i of tempList to (item i of tempList) + 1
if item i of tempList ≤ item i of {blocks, rows, columns} then
copy tempList to end of pathCheckList
end if
end repeat
return pathCheckList
end processPathList:
on filterColorsByList:aList
set filteredList to {}
set colorListRef to a reference to colorList
repeat with aColor in colorListRef
if aColor is not in aList then
copy aColor as text to end of filteredList
end if
end repeat
return filteredList
end filterColorsByList: