16
\$\begingroup\$

The question score on Stack Exchange is the total number of upvotes minus the total number of downvotes a question receives. However, the reputation gained/lost for every upvote/downvote is different (eg. 10/-2 on Code Golf).

Given the total reputation earned, the reputation gained by an upvote and the reputation lost by a downvote, list out all possible scores (unweighted, +1/-1 for upvote/downvote) the question could have).

Rules

  • The total reputation and the reputation per vote must be integers
  • The upvote-reputation will be positive and the downvote-reputation will be negative
  • Impossible question scores are not valid inputs
  • You can output the possible question scores as an infinite list or generator, print each individually, etc.
  • This is , so the shortest answer wins

Examples

[total reputation, upvote-reputation, downvote-reputation] -> [question scores]

[28, 10, -2]  -> [2, -2, -6, -10, ...]
[34, 10, -2]  -> [1, -3, -7, -11, ...]
[11, 7, -5]   -> [1, -1, -3, -5, ...]
[82, 31, -11] -> [2, -18, -38, -58, ...]
[15, 5, -10]  -> [3, 4, 5, 6, ...]
[-38, 4, -9]  -> [-2, 3, 8, 13, ...]
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Are we allowed to output the same score more than once? \$\endgroup\$
    – bsoelch
    Sep 12 at 14:24
  • \$\begingroup\$ @bsoelch sure, why not \$\endgroup\$
    – math scat
    Sep 12 at 14:28
  • 3
    \$\begingroup\$ "all possible scores the question could have" Might be worth clarifying that "possible scores" here means unweighted score, where and upvote is +1 and a downvote is -1. \$\endgroup\$
    – Jonah
    Sep 13 at 0:36

6 Answers 6

7
\$\begingroup\$

Python, 92 bytes

-2 bytes, thanks to UndoneStudios
-7 bytes, thanks to SuperStormer

lambda s,u,d:(a-b*2for a in count()for b in range(a)if(a-b)*u+b*d==s)
from itertools import*

Attempt This Online!

outputs a generator

99 bytes without using itertools:

lambda s,u,d:(a-b*2for a in N()for b in range(a)if(a-b)*u+b*d==s)
def N(i=0):
 while 1:yield i;i+=1

Attempt This Online!

Explanation

Goes through all pairs (x,y) of non-negative integers and checks if x upvotes and y downvotes gives the right score


Python, 115 bytes

def f(s,u,d):
 i=s<0;g=math.gcd(u,d);a=s*pow(d//g,-1,u//g)%u/g
 while 1:yield(s-d*a)/u-a-i*(u+d)/g;i+=1
import math

Attempt This Online!

Direct solution, sadly longer than brute force

from math import* is not possible, as it will overwrite pow

Explanation

  1. Solve b*u+a*d=s by using s=a*d mod u -> a=d⁻¹*s mod u (dividing out the gcd of u and d to ensure inverting d is possible)
  2. compute b from a
  3. The possible scores are (b-a)+k*gcd(u,d) for an integer k
\$\endgroup\$
2
  • \$\begingroup\$ What about yield i;i+=1 or the other way round, if needed? \$\endgroup\$ Sep 12 at 14:31
  • 2
    \$\begingroup\$ 92 bytes \$\endgroup\$ Sep 12 at 21:59
6
\$\begingroup\$

05AB1E, 17 14 12 bytes

-5 bytes (and even slower than before 😅) thanks to @CommandMaster.

∞Óʒ¹*OQ}ε2£Æ

Two separated inputs \$[upvoteRep,downvoteRep]\$ and \$totalRep\$.
Outputs an infinite list that includes duplicated items.

Try it online. (Extremely slow brute-force that barely outputs the first two unique terms of the example test case, so no test suite with all test cases.)

We can prevent the duplicated items for +2 bytes by adding a trailing :
Try it online.

Earlier 14 bytes answer (partially also by @CommandMaster) that's a lot faster:

∞Ý€ã€`ʒ¹*OQ}€Æ

Similar I/O as above.

Try it online.

We can prevent the duplicated items for +1 byte this time by adding a trailing Ù:
Try it online or verify the first five values of all test cases.

Explanation:

∞        # Push an infinite list of positive integers: [1,2,3,...]
 Ó       # Convert each to a list of exponents of its prime factorization:
         #  [[],[1],[0,1],[2],[0,0,1],[1,1],[0,0,0,1],[3],[0,2],[1,0,1],...]
ʒ¹*OQ}   # Only keep all valid lists for the given inputs:
ʒ    }   #  Filter this infinite list of lists by:
 ¹*      #   Multiply the first two values in the list by the first input-pair of
         #   [pos,neg] (or if it's a singleton list, multiply its value by just `pos`)
   O     #   Sum this pair (or singleton)
    Q    #   Check whether it's equal to the second (implicit) input-integer
ε2£Æ     # Calculate the question-scores of the remaining valid lists:
ε        #  Map over each remaining list in the infinite list:
 2£      #   Only keep (up to) the first 2 values
   Æ     #    Reduce it by subtracting: [a,b]→a-b or [a]→a
    }Ù   # (optional) Close the map, and uniquify this infinite list of values
         # (after which the infinite list of scores is output implicitly as result)
∞Ý€ã€`   # Generate an infinite list of non-negative pairs:
∞        #  Push an infinite list of positive integers: [1,2,3,...]
 Ý       #  Convert each value to a [0,v]-ranged list: [[0,1],[0,1,2],[0,1,2,3],...]
  ۋ     #  Map over each list, and get its cartesian power of 2 to create pairs:
         #   [[[0,0],[0,1],[1,0],[1,1]],[[0,0],[0,1],[0,2],[1,0],...],...]
    €`   #  Flatten the list of lists of pairs one level down:
         #   [[1,1],[1,0],[0,1],[0,0],[2,2],[2,1],[2,0],[1,2],[1,1],[1,0],...]
ʒ¹*OQ}   # Only keep all valid pairs for the given inputs:
ʒ    }   #  Filter this infinite list of pairs by:
 ¹*      #   Multiply the values in the pair by the first input-pair of [pos,neg]
   O     #   Sum the values in this pair together
    Q    #   Check whether it's equal to the second (implicit) input-integer
ۮ       # Calculate the question-scores of the remaining valid pairs:
€        #  Map over each remaining pair in the infinite list:
 Æ       #   Reduce the pair by subtracting: [a,b]→a-b
  Ù      # (optional) Uniquify this infinite list of values
         # (after which the infinite list of scores is output implicitly as result)
\$\endgroup\$
9
  • 1
    \$\begingroup\$ -3 by ∞<€Dæ2ù€Â -> ∞·Ó2ù< (although it's even slower) \$\endgroup\$ Sep 13 at 3:11
  • 1
    \$\begingroup\$ ∞Ý€ã€` also works for 6 bytes to that part and is much faster \$\endgroup\$ Sep 13 at 3:17
  • 1
    \$\begingroup\$ @CommandMaster Although your 12-byter is very clever, I'm afraid it won't always work. E.g. inputs [-1,10], -3 will also include [3] after the filter, because 3*-1=-3 and the 10 in the input-pair is ignored. Thanks a lot for the shorter generation of infinite pairs, though! I had the feeling that could be shorter (and faster), but couldn't figure it out earlier. \$\endgroup\$ Sep 13 at 7:32
  • 1
    \$\begingroup\$ Oh, didn't think of that. I think this fixes that \$\endgroup\$ Sep 13 at 7:45
  • 1
    \$\begingroup\$ It isn't needed, you can see with [2, 2, -1] as a testcase \$\endgroup\$ Sep 13 at 8:41
5
\$\begingroup\$

Ruby, 60 49 bytes

->r,u,d{0.step{|a|q=r-d*a;q%u<1&&q>-u&&p(q/u-a)}}

Try it online!

For any number of downvotes, check if the difference between the score and the sum of downvotes can be divided by the upvote score.

\$\endgroup\$
5
\$\begingroup\$

Python 3,  72 67 66 65 57  55 bytes

-6 thanks to xnor! (Inlining the while loop by use of (yield ...) being None, in turn allowing for post-incrementing. Suggesting printing.)
-7 more thanks to xnor! (Refactor to a recursive function.)
-2 thanks to Neil (Since d is guaranteed to be negative 0<=r/d may be replaced with 0>=r).

def f(r,u,d,p=0):r%d==0>=r!=print(p-r/d);f(r-u,u,d,p+1)

A function that accepts the reputation, r, the upvote delta, u and the downvote delta, d, and prints the potential scores forever.

Try it online! (Harnessed to halt printing early.)

How?

p is the upvote count and is initialised to 0 for the first call in the function's parameters (,p=0). Subsequent calls (f(r-u,u,d,p+1)) are each for one more upvote (p+1) and for the outstanding reputation (r-u).

Each call evaluates whether any non-negative (0>=r) integer number of downvotes is valid (r%d==0) and prints the upvotes less the downvotes (print(p-r/d)) if so (when != is reached causing evaluation).

\$\endgroup\$
9
  • \$\begingroup\$ awesome, love the solution! \$\endgroup\$
    – math scat
    Sep 13 at 19:39
  • \$\begingroup\$ 66 bytes \$\endgroup\$
    – xnor
    Sep 13 at 23:04
  • \$\begingroup\$ The challenge allows printing forever rather than using yield. \$\endgroup\$
    – xnor
    Sep 13 at 23:12
  • \$\begingroup\$ Thanks @xnor. I'd tried and(yield ...) at some point and it hadn't worked, no doubt I had a bug somewhere! \$\endgroup\$ Sep 13 at 23:37
  • \$\begingroup\$ 57 bytes by recursing \$\endgroup\$
    – xnor
    Sep 13 at 23:48
5
\$\begingroup\$

Rust, 127 123 93 bytes

Port of @G B's Ruby anwser in Rust.

Saved 30 bytes thanks to the comment of @c--


Golfed version. Try it online!

|r,u,d|(|mut a,mut b|loop{if a*u+b*d==r{print!("{}
",a-b)}if a*u+b*d>r{b+=1}else{a+=1}})(0,0)

Ungolfed version. Try it online!

fn find_pairs(r: i32, u: i32, d: i32) {
    let mut a = 0;
    let mut b = 0;
    
    loop {
        let z = a * u + b * d;
        
        if z > r {
            b += 1;
        } else if z == r {
            println!("{}", a - b);
            a += 1;
        } else {
            a += 1;
        }
    }
}

fn main() {
    find_pairs(28, 10, -2);
}
\$\endgroup\$
1
  • \$\begingroup\$ 93 bytes \$\endgroup\$
    – c--
    Sep 20 at 16:17
4
\$\begingroup\$

Charcoal, 44 bytes

NθNηNζ≦⁻×⁺ηζ∧›θ⁰±÷θ±ηθW¹«F¬﹪θζ«I÷θζD⎚»≧⁺⁺ηζθ

Try it online! Link is to verbose version of code. Explanation:

NθNηNζ

Input the question, upvote and downvote reputations.

≦⁻×⁺ηζ∧›θ⁰±÷θ±ηθ

If the question reputation is positive, adjust it for the minimum number of upvotes required. If it is negative, just negate it.

W¹«

Repeat indefinitely.

F¬﹪θζ«I÷θζD⎚»

If the question reputation is a multiple of the downvote reputation then output the possible score.

≧⁺⁺ηζθ

Add both the upvote and downvote reputations to the question reputation. This allows the score to be determined solely from the downvote reputation.

Note that the behaviour on TIO is for Dump to pause 10ms since the last Dump, meaning that the script usually times out after printing 6000 possible scores. The newer version of Charcoal on ATO supports the --nt option which disables this pause, allowing it to fill the 128KB output buffer instead. Attempt This Online! Link is to verbose version of code.

\$\endgroup\$
1
  • \$\begingroup\$ Great solution! \$\endgroup\$
    – math scat
    Sep 13 at 5:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.