一尘不染

高尔夫代码:倒计时数字游戏

algorithm

挑战

这是受英国著名电视游戏节目 Countdown 启发而来的任务。即使没有任何游戏知识,挑战也应该很清楚,但请随时提出澄清。

而且,如果您希望看到该游戏的片段,请查看YouTube片段。它以1997年出色的已故RichardWhitely为特色。

系统会为您提供6个数字,这些数字是从{1、2、3、4、5、6、8、9、10、25、50、75、100}集中随机选择的,并且有100到999之间的随机目标数字。目的是使用六个给定的数字和四个常见的算术运算(加法,减法,乘法,除法;遍及有理数)来生成目标-
或尽可能靠近任一侧。每个数字最多只能使用一次,而每个算术运算符可以使用任意次(包括零次)。请注意,使用多少个数字都没有关系。

编写一个函数,该函数采用目标数字和6个数字的集合(可以表示为列表/集合/数组/序列),并以任何标准数字符号(例如,中缀,前缀,后缀)返回解决方案。该功能必须
始终将最可能的结果返回给目标 ,并且必须在标准PC上最多运行1分钟。注意,在存在多个解决方案的情况下,任何一个解决方案都足够。

例子:

  • {50,100,4,2,2,2,4},目标203,
    例如100 * 2 + 2 +(4/4) (精确),
    例如(100 + 50)* 4 * 2 /(4 + 2) (精确)

  • {25、4、9、2、3、10},目标465,
    例如(25 + 10-4 )*(9 * 2-3) (精确)

  • {9,8,10,5,9,7},目标241
    例如(((10 + 9)* 9 * 7)+ 8)/ 5 (精确)

  • {3,7,6,2,1,1,7},目标824
    例如(((7 * 3)-1) 6-2 7 (= 826;偏离2)

规则

除了问题陈述中提到的内容外,没有其他限制。您可以用任何标准语言编写该函数(不需要标准I / O)。一如既往的目标是用最少数量的代码字符解决任务。

话虽如此,我可能不会简单地接受使用最短代码的答案。我还将研究代码的优美性和算法的时间复杂性!

我的解决方案

找到空闲时间后,我正在尝试F#解决方案-当我有空的时候将其张贴在这里!


格式

为了便于比较,请以以下格式发布所有答案:

语言

字符数:???

完全模糊的功能:

(code here)

清除(理想注释)功能:

(code here)

关于算法/智能快捷键的所有注释。



阅读 244

收藏
2020-07-28

共1个答案

一尘不染

哈斯克尔

字符数: 361 350 338 322

完全模糊的功能:

m=map
f=toRational
a%w=m(\(b,v)->(b,a:v))w
p[]=[];p(a:w)=(a,w):a%p w
q[]=[];q(a:w)=[((a,b),v)|(b,v)<-p w]++a%q w
z(o,p)(a,w)(b,v)=[(a`o`b,'(':w++p:v++")")|b/=0]
y=m z(zip[(-),(/),(+),(*)]"-/+*")++m flip(take 2 y)
r w=do{((a,b),v)<-q w;o<-y;c<-o a b;c:r(c:v)}
c t=snd.minimum.m(\a->(abs(fst a-f t),a)).r.m(\a->(f a,show a))

清除功能:

-- | add an element on to the front of the remainder list
onRemainder :: a -> [(b,[a])] -> [(b,[a])]
a`onRemainder`w = map (\(b,as)->(b,a:as)) w

-- | all ways to pick one item from a list, returns item and remainder of list
pick :: [a] -> [(a,[a])]
pick [] = []
pick (a:as) = (a,as) : a `onRemainder` (pick as)

-- | all ways to pick two items from a list, returns items and remainder of list
pick2 :: [a] -> [((a,a),[a])]
pick2 [] = []
pick2 (a:as) = [((a,b),cs) | (b,cs) <- pick as] ++ a `onRemainder` (pick2 as)

-- | a value, and how it was computed
type Item = (Rational, String)

-- | a specification of a binary operation
type OpSpec = (Rational -> Rational -> Rational, String)

-- | a binary operation on Items
type Op = Item -> Item -> Maybe Item

-- | turn an OpSpec into a operation
-- applies the operator to the values, and builds up an expression string
-- in this context there is no point to doing +0, -0, *0, or /0
combine :: OpSpec -> Op
combine (op,os) (ar,as) (br,bs)
    | br == 0   = Nothing
    | otherwise = Just (ar`op`br,"("++as++os++bs++")")

-- | the operators we can use
ops :: [Op]
ops = map combine [ ((+),"+"), ((-), "-"), ((*), "*"), ((/), "/") ]
        ++ map (flip . combine) [((-), "-"), ((/), "/")]

-- | recursive reduction of a list of items to a list of all possible values
-- includes values that don't use all the items, includes multiple copies of
-- some results          
reduce :: [Item] -> [Item]
reduce is = do
    ((a,b),js) <- pick2 is
    op <- ops
    c <- maybe [] (:[]) $ op a b
    c : reduce (c : js)

-- | convert a list of real numbers to a list of items
items :: (Real a, Show a) => [a] -> [Item]
items = map (\a -> (toRational a, show a))

-- | return the first reduction of a list of real numbers closest to some target
countDown:: (Real a, Show a) => a -> [a] -> Item
countDown t is = snd $ minimum $ map dist $ reduce $ items is
    where dist is = (abs . subtract t' . fst $ is, is)
          t' = toRational t

关于算法/智能快捷方式的任何注释:

  • 在golf’d版本,z在列表单子的回报,而不是Maybeops做。
  • 尽管这里的算法是蛮力的,但由于Haskell的惰性,它在较小的固定的线性空间中运行。我编写了很棒的@ keith-randall算法,但它同时运行,并在Haskell中接管了1.5G的内存。
  • reduce 多次生成一些答案,以便轻松包含术语更少的解决方案。
  • 在高尔夫球版中,y部分是根据自身定义的。
  • 结果用Rational值计算。Golf的代码将缩短17个字符,如果使用进行计算,则将更快Double
  • 请注意,函数是如何onRemainder排除pick和之间结构相似性的pick2

高尔夫版驱动程序:

main = do
    print $ c 203 [50, 100, 4, 2, 2, 4]
    print $ c 465 [25, 4, 9, 2, 3, 10]
    print $ c 241 [9, 8, 10, 5, 9, 7]
    print $ c 824 [3, 7, 6, 2, 1, 7]

按时间运行(每个结果还不到一分钟):

[1076] : time ./Countdown
(203 % 1,"(((((2*4)-2)/100)+4)*50)")
(465 % 1,"(((((10-4)*25)+2)*3)+9)")
(241 % 1,"(((((10*9)/5)+8)*9)+7)")
(826 % 1,"(((((3*7)-1)*6)-2)*7)")

real    2m24.213s
user    2m22.063s
sys     0m 0.913s
2020-07-28