chess123mate

Roblox Snack Break #27

Jan 7th, 2018
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.33 KB | None | 0 0
  1. function Encode0(t)
  2.     table.sort(t)
  3.     local enc = {} -- string
  4.     local min, max
  5.     local function submit()
  6.         if not min then return end
  7.         enc[#enc+1] = min == max
  8.             and min
  9.             or string.format("%s-%s", min, max)
  10.     end
  11.     local function add(v)
  12.         if max == v - 1 then -- extend max
  13.             max = v
  14.             return
  15.         elseif min then
  16.             submit()
  17.         end
  18.         min, max = v, v
  19.     end
  20.     for i = 1, #t do
  21.         add(t[i])
  22.     end
  23.     submit()
  24.     return table.concat(enc, ", ")
  25. end
  26. function Encode1(t)
  27.     table.sort(t)
  28.     local enc = {} -- string
  29.     local min, max, rep
  30.     local function submit()
  31.         if not min then return end
  32.         enc[#enc+1] =
  33.             min == max and
  34.                 (rep == 1 and min
  35.                     or string.format("%s x%s", min, rep))
  36.             or min + 1 == max and string.format("%s, %s", min, max)
  37.             or string.format("%s-%s", min, max)
  38.     end
  39.     local function add(v)
  40.         if v - 1 == max and (not rep or rep == 1) then -- extend max
  41.             max = v
  42.             return
  43.         elseif v == max then -- add repetition
  44.             if min ~= max then
  45.                 max = max - 1 -- return max to prev value
  46.                 submit()
  47.             end
  48.             min, max = v, v
  49.             rep = rep + 1
  50.             return
  51.         elseif min then -- submit what exists
  52.             submit()
  53.         end
  54.         min, max, rep = v, v, 1
  55.     end
  56.     for i = 1, #t do
  57.         add(t[i])
  58.     end
  59.     submit()
  60.     return table.concat(enc, ", ")
  61. end
  62. --Level 2
  63. --[[Algorithm
  64. As we proceed, reduce to objects, not string
  65. Only stringify at end
  66. Objects:
  67. (Each number given to .Add is wrapped in 'Single')
  68. Single (1)
  69.     .Add(2) -> Range
  70.     .Add(Range(2, 3)) -> Range(1, 3)
  71.     .Add(self) -> Duplicate(self, 2)
  72. Range (1, 2)
  73.     .Add(2) -> Single(1) + Duplicate(2, 2) [this is for duos only]
  74.     .Add(3) -> Range(1, 3)
  75.     .Add(Range(3,4)) -> Range(1, 4)
  76.     .Add(self) -> Duplicate(self, 2)
  77. Duplicate (1 x2)
  78.     .Add(value equivalent to self value) -> Duplicate(self, 3)
  79.     .Add(Duplicate with value equivalent to self value)
  80.         -> Duplicate(self, self rep + arg rep)
  81. More specific algorithm:
  82. 1. Wrap all table items in Single
  83. 2. Apply Add algorithm
  84.     If NoChange, go to next item
  85.     For all other options, record "changeMade"
  86.     If AbsorbNext or ReplaceBoth, delete next item from table
  87.     If ReplaceBoth, replace cur item with new one
  88.     If ReplaceBothTwoNew, replace cur item with new one and next item with 2nd new one
  89. 3. When no more items, repeat entire loop if "changeMade"
  90. 4. Now we have to search for multi-item patterns
  91.     -We must attempt to find the largest pattern available
  92. Each type is to have these functions:
  93. :Add(value):Return (see below), value1, value2
  94. :Equals(value):bool
  95. :GetMinValue() -- is to be nil for duplicate
  96. :GetMaxValue() -- is to be nil for duplicate
  97. :GetSingleValue() -- is to be nil for everything except Single
  98. :GetNumRepetitions() -- must be a number (often 1)
  99. :GetInnerValue() -- must return self (if not duplicate) or else the duplicate's contained value
  100. :ToString()
  101. ]]
  102. --.Add returns:
  103. local NoChange = 0
  104. local AbsorbNext = 1
  105. local ReplaceBoth = 2
  106. local ReplaceBothTwoNew = 3
  107. local Single, Range, Duplicate
  108. local function IsDuplicate(a, b)
  109.     return a:GetInnerValue():Equals(b:GetInnerValue())
  110. end
  111. local function Merge(a, b)
  112.     return Duplicate(
  113.         a:GetInnerValue(),
  114.         a:GetNumRepetitions() + b:GetNumRepetitions())
  115. end
  116. local function HandleDuplicate(self, v)
  117.     if IsDuplicate(self, v) then
  118.         return ReplaceBoth, Merge(self, v)
  119.     end
  120.     return NoChange
  121. end
  122. function Single(num)
  123.     return {
  124.         GetSingleValue = function() return num end,
  125.         GetMinValue = function() return num end,
  126.         GetMaxValue = function() return num end,
  127.         GetNumRepetitions = function() return 1 end,
  128.         GetInnerValue = function(self) return self end,
  129.         Add = function(self, v)
  130.             if v:GetNumRepetitions() == 1 and v:GetMinValue() == num + 1 then
  131.                 -- if num repetitions > 1, it's something like "5, 6 x2" (so no change)
  132.                 return ReplaceBoth, Range(num, v:GetMaxValue())
  133.             end
  134.             return HandleDuplicate(self, v)
  135.         end,
  136.         Equals = function(self, v)
  137.             return v:GetSingleValue() == num and v:GetNumRepetitions() == 1
  138.         end,
  139.         ToString = function()
  140.             return num
  141.         end,
  142.     }
  143. end
  144. function Range(min, max)
  145.     return {
  146.         GetSingleValue = function() return nil end,
  147.         GetMinValue = function() return min end,
  148.         GetMaxValue = function() return max end,
  149.         GetNumRepetitions = function() return 1 end,
  150.         GetInnerValue = function(self) return self end,
  151.         Add = function(self, v)
  152.             if v:GetSingleValue() == max and min + 1 == max then -- split duo-range into single & duplicate
  153.                 return ReplaceBothTwoNew, Single(min), Duplicate(Single(max), 2)
  154.             elseif v:GetMinValue() == max + 1 and v:GetNumRepetitions() == 1 then -- extend
  155.                 max = v:GetMaxValue()
  156.                 return AbsorbNext
  157.             end
  158.             return HandleDuplicate(self, v)
  159.         end,
  160.         Equals = function(_, v)
  161.             return v:GetMinValue() == min and v:GetMaxValue() == max and v:GetNumRepetitions() == 1
  162.         end,
  163.         ToString = function()
  164.             return min == max - 1
  165.                 and string.format("%s, %s", min, max)
  166.                 or string.format("%s-%s", min, max)
  167.         end,
  168.     }
  169. end
  170. function Duplicate(v, count)
  171.     if type(v) ~= "table" then error("v must be an object, not " .. tostring(v)) end
  172.     if type(count) ~= "number" or count < 2 then error("count must be >=2, not " .. tostring(count)) end
  173.     return {
  174.         GetSingleValue = function() return nil end,
  175.         GetMinValue = function() return nil end,
  176.         GetMaxValue = function() return nil end,
  177.         GetNumRepetitions = function() return count end,
  178.         GetInnerValue = function(self) return v end,
  179.         Add = HandleDuplicate,
  180.         Equals = function(_, v2)
  181.             return v2 ~= v2:GetInnerValue() and v2:GetInnerValue():Equals(v) and v2:GetNumRepetitions() == count
  182.         end,
  183.         ToString = function()
  184.             return string.format(
  185.                 v:GetSingleValue()
  186.                     and "%s x%s"
  187.                     or "(%s) x%s",
  188.                 v:ToString(),
  189.                 count)
  190.         end,
  191.         IncrementCount = function() count = count + 1 end, --for ExtendPatterns only
  192.     }
  193. end
  194. local function Pattern(items)
  195.     return {
  196.         IsPatternEqual = function(self, t, i) --t is table of items to compare with, 'i' is t's starting index (for comparison purposes)
  197.             for j = 1, #items do
  198.                 if not items[j]:Equals(t[i+j-1]) then
  199.                     return false
  200.                 end
  201.             end
  202.             return true
  203.         end,
  204.         GetPatternLength = function() return #items end,
  205.         GetItems = function() return items end,
  206.         Equals = function(self, v)
  207.             v = v.GetItems and v:GetItems()
  208.             if not v then return end
  209.             for i = 1, #items do
  210.                 if not items[i]:Equals(v[i]) then
  211.                     return false
  212.                 end
  213.             end
  214.             return true
  215.         end,
  216.         ToString = function()
  217.             local s = {}
  218.             for i = 1, #items do
  219.                 if i > 1 then
  220.                     s[#s + 1] = ", "
  221.                 end
  222.                 s[#s + 1] = items[i]:ToString()
  223.             end
  224.             return table.concat(s)
  225.         end,
  226.         --These functions for the sake of Duplicate and merging:
  227.         GetSingleValue = function() return nil end,
  228.         GetNumRepetitions = function() return 1 end,
  229.         GetInnerValue = function(self) return self end,
  230.         --GetMinValue/GetMaxValue/Add not needed
  231.     }
  232. end
  233. function Encode2(t)
  234.     --Wrap all table items in Single
  235.     for i = 1, #t do
  236.         t[i] = Single(t[i])
  237.     end
  238.     --Apply Add to all items
  239.     local noChangesMade, i, status, a, b
  240.     repeat
  241.         noChangesMade = true
  242.         i = 1
  243.         while t[i + 1] do
  244.             status, a, b = t[i]:Add(t[i + 1])
  245.             if status == NoChange then
  246.                 i = i + 1
  247.             else
  248.                 noChangesMade = false
  249.                 if status == AbsorbNext or status == ReplaceBoth then
  250.                     table.remove(t, i + 1)
  251.                 end
  252.                 if status == ReplaceBoth or status == ReplaceBothTwoNew then
  253.                     t[i] = a
  254.                     if status == ReplaceBothTwoNew then
  255.                         t[i + 1] = b
  256.                     end
  257.                 end
  258.             end
  259.         end
  260.     until noChangesMade
  261.     --Look for multi-item patterns.
  262.     --To start with, get rid of any duo-ranges (which can mess up pattern detection when there is a "3, 2, 3, 2" sequence -- the middle "2, 3" is otherwise ignored):
  263.     for i = 1, #t do
  264.         local min, max = t[i]:GetMinValue(), t[i]:GetMaxValue()
  265.         if min and max and min + 1 == max then
  266.             t[i] = Single(min)
  267.             table.insert(t, i + 1, Single(max))
  268.         end
  269.     end
  270.     local function FindPatterns()
  271.         for size = 2, math.floor(#t/2) do
  272.             --a, b, c, d, e
  273.             --size 2 means we want to check (a,b) vs (c,d) and (b,c) vs (d,e)
  274.             --thus, max initial index is 'b', or #t - size*2 + 1
  275.             local equal
  276.             for i = 1, #t - size * 2 + 1 do
  277.                 equal = true
  278.                 for j = i, i + size - 1 do
  279.                     if not t[j]:Equals(t[j + size]) then
  280.                         equal = false
  281.                         break
  282.                     end
  283.                 end
  284.                 if equal then
  285.                     --Gather items that are duplicates
  286.                     local items = {}
  287.                     for j = i, i + size - 1 do
  288.                         items[#items+1] = t[j]
  289.                     end
  290.                     --Remove them from the table in both places they exist
  291.                     for j = i + size * 2 - 1, i + size, -1 do
  292.                         table.remove(t, j)
  293.                     end
  294.                     for j = i + size - 1, i + 1, -1 do
  295.                         table.remove(t, j)
  296.                     end
  297.                     t[i] = Duplicate(Pattern(items), 2)
  298.                     return true
  299.                 end
  300.             end
  301.         end
  302.         return false
  303.     end
  304.     local function ExtendPatterns()
  305.         local pattern
  306.         for i = 1, #t - 1 do
  307.             pattern = t[i]:GetInnerValue()
  308.             pattern = pattern.IsPatternEqual and pattern or nil
  309.             if pattern and pattern:IsPatternEqual(t, i + 1) then
  310.                 for j = i + pattern:GetPatternLength(), i + 1, -1 do
  311.                     table.remove(t, j)
  312.                 end
  313.                 t[i]:IncrementCount()
  314.                 return true
  315.             end
  316.         end
  317.         return false
  318.     end
  319.     while FindPatterns() do while ExtendPatterns() do end end
  320.     --ToString
  321.     local enc = {}
  322.     for i = 1, #t do
  323.         enc[i] = t[i]:ToString()
  324.     end
  325.     return table.concat(enc, ", ")
  326. end
  327.  
  328. local function Test(a, b)
  329.     return {Data = a, Expected = b}
  330. end
  331. local function RunTests(setName, tests, func)
  332.     local total, good = 0, 0
  333.     for i = 1, #tests do
  334.         total = total + 1
  335.         local v = func(tests[i].Data)
  336.         if v == tests[i].Expected then
  337.             good = good + 1
  338.         else
  339.             print(setName, "Test", i, "failed:", v, "~=", tests[i].Expected)
  340.         end
  341.     end
  342.     print(string.format("%s tests: %s/%s correct", setName, good, total))
  343. end
  344. local tests0 = {
  345.     Test({1, 2, 3, 4}, "1-4"),
  346.     Test({7, 4, 6, 2, 8}, "2, 4, 6-8"),
  347.     Test({1, -2, 3, -4, 5, 6}, "-4, -2, 1, 3, 5-6"),
  348.     Test({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "1-10"),
  349.     Test({1, 2, 5, 6, 7}, "1-2, 5-7"),
  350.     Test({0}, "0"),
  351.     Test({}, ""),
  352. }
  353. local tests1 = {
  354.     Test({2, 1, 1, 1, 0}, "0, 1 x3, 2"),
  355.     Test({1, 2, 5, 6, 7}, "1, 2, 5-7"),
  356.     Test({1, 1, 2, 3, 4}, "1 x2, 2-4"),
  357.     Test({1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 2, 2, 3, 3, 4, 4}, "1 x4, 2 x4, 3 x4, 4 x4"),
  358. }
  359. local tests2 = {
  360.     Test({1, 2, 3, 4}, "1-4"),
  361.     Test({4, 2, 3, 1}, "4, 2, 3, 1"),
  362.     Test({1, 2, 1, 2}, "(1, 2) x2"),
  363.     Test({1, 2, 1, 2, 1, 2, 1, 2}, "(1, 2) x4"),
  364.     Test({1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7}, "(1 x2, 2 x2, 3 x2, 4 x2) x2, 5-7"),
  365.     Test({0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2}, "0, (1 x2, 2 x2) x3"),
  366.     Test({1, 1, 1, 1, 5, 1, 5}, "1 x4, 5, 1, 5"), --[[NOTE: Original test requires this:
  367.     Test({1, 1, 1, 1, 5, 1, 5}, "1 x3, (1, 5) x2"),
  368.     but without a more complicated algorithm, I don't see how to do that.
  369.     Further, if you consider how you'd encode the representation, it is less efficient than "1 x4, 5, 1, 5":
  370.     #s to encode each component:
  371.         Single = 2: Type + Value
  372.         List of single = 2 + #values: Type + Count + Values (good for 2+)
  373.         Range = 3: Type + Min + Max
  374.         Duplicate = 2+valueCost: Type + (Value Encoding) + Duplicate Count
  375.         Pattern = 2+valueCost: Type + Length + (values encoding)
  376.         (There may be more efficient encodings but this is the easiest I could think of)
  377.     "1 x3, (1, 5) x2": Duplicate(Single), Duplicate(Pattern(Single, Single))
  378.         = 2+2 + 2+2+2+2 = 12
  379.     "1, 1, 1, 1, 5, 1, 5" is just a list of 7 singles, or 2+7=9
  380.         If you don't allow List, it's 2*7=14
  381.     "1 x4, 5, 1, 5" = Duplicate(Single), List<Single> = 4 + 5=9
  382.         or (if you disallow List) 4 + 2*3=10
  383.     Thus, "1 x4, 5, 1, 5" ties with "1, 1, 1, 1, 5, 1, 5" if you allow List<Single>
  384.         and in all cases "1 x3, (1, 5) x2" is less efficient than "1 x4, 5, 1, 5"
  385.     ]]
  386.     Test({1, 1, 1, 1, 5, 1, 5, 1}, "1 x4, (5, 1) x2"),
  387. }
  388. tests3 = {
  389.     Test({1, 3, 5, 1, 2, 1, 2, 1, 2, 7, 9, 5, 1, 3, 5, 1, 2, 1, 2, 1, 2, 7, 9, 5},
  390.         "(1, 3, 5, (1, 2) x3, 7, 9, 5) x2"),
  391.     Test({6, 2, 2, 6, 2, 2, 6, 2, 2, 1, 3, 2, 3, 2, 5, 1, 3, 2, 3, 2, 5, 7},
  392.         "(6, 2 x2) x3, (1, (3, 2) x2, 5) x2, 7"),
  393. }
  394. local function Set(a, b, c)
  395.     return {Name = a, Tests = b, Func = c}
  396. end
  397. local allTests = {
  398.     Set("Level 0", tests0, Encode0),
  399.     Set("Level 1", tests1, Encode1),
  400.     Set("Level 2", tests2, Encode2),
  401.     Set("Level 3", tests3, Encode2), -- Could make Encode2 fit "Level2"'s implied limitation by refusing to allow a Pattern in a Pattern, but not worth it
  402. }
  403. for i = 1, #allTests do
  404.     RunTests(allTests[i].Name, allTests[i].Tests, allTests[i].Func)
  405. end
Advertisement
Add Comment
Please, Sign In to add comment