20
\$\begingroup\$

Introduction

For those not familiar with steam - or at least this particular aspect:

Often on peoples' profiles, people leave comments saying either "+rep _____" or "-rep _____". These are an unofficial means of showing whether you think someone in the community has a good or a bad reputation, for a number of reasons. Such comments look like:

+rep a good player

+rep helpful

-rep hacker

-rep scammer


Task

The program must take input through any consensual way. The input consists of a string with optional newlines (\n). At the very start of each line, '+rep ' or '-rep ' might be present. The rest of the line can be discarded. If the line doesn't start with '+rep ' or '-rep ' (note the trailing space), the line should be ignored.

The program then must keep a total reputation score. Starting at 0, this score should be incremented on every line that starts with '+rep ' and decremented on every line that starts with '-rep '.

This result should be output in any agreed-upon way.


Test cases

Input:
+rep fast trade
+rep nice person
-rep too good

Output: 1

Input:
-rep hacker
-rep scammer
-rep was mean

Output: -3

Input:
first
i don't like him
+rep good at cs go

Output: 1

Input (note the lack of a trailing space on the third line):    
+rep +rep
hi +rep
-rep

Output: 1

Input:
+ rep

Output: 0

Input:
+rep like
-thing

Output: 1

Bonus

I don't even know if it's possible, but bonus points if you can somehow get these comments from Steam.

\$\endgroup\$
21
  • 5
    \$\begingroup\$ Assuming the bonus points are imaginary, correct? They don't actually affect your score. \$\endgroup\$
    – Riker
    Apr 10, 2017 at 13:39
  • 2
    \$\begingroup\$ Can we assume the only plus and minus signs are in the '+rep'/'-rep'? Will the rep only be at the start of the line, or could it be in the middle also? \$\endgroup\$
    – Riker
    Apr 10, 2017 at 13:44
  • 3
    \$\begingroup\$ I would recommend adding a test case where there is a +rep or -rep that isn't at the start of the line \$\endgroup\$ Apr 10, 2017 at 14:13
  • 3
    \$\begingroup\$ I believe that example 4 should have output 0, not 1. \$\endgroup\$
    – DJMcMayhem
    Apr 10, 2017 at 17:54
  • 10
    \$\begingroup\$ Hi Jacob, and welcome to PPCG. You've managed to get a quite active conversation for your first challenge here! Since no one else has yet mentioned it, I'll direct you to the Sandbox where you can get meaningful feedback and hammer out any details or clarification issues before posting the challenge to Main. In the future, that will help you avoid downvotes, closevotes, and the like. I hope you stick around and enjoy your stay! \$\endgroup\$ Apr 10, 2017 at 18:02

19 Answers 19

10
\$\begingroup\$

Python 3, 73 bytes

I'm sure this answer is garbage and will be beaten soon, but there's no other python answers yet

lambda x:sum(["- +".index(i[0])-1for i in x.split('\n')if i[1:4]=="rep"])

Use like this:

f = lambda x:sum(["- +".index(i[0])-1for i in x.split('\n')if i[1:4]=="rep"])
print(f("PUT INPUT HERE"))


Fetching from steam

Here's some sample code which fetches the first 100 comments from KennyS' profile and calculates his rep.

import requests
from bs4 import BeautifulSoup

# Kenny's profile as Steam ID 64
# You can adjust this to whatever numbers you want
STEAM_PROFILE_URL = "76561198024905796"
payload =  {"start" : 0, "count" : 100}
r = requests.post("http://steamcommunity.com/comment/Profile/render/{}/-1/".format(STEAM_PROFILE_URL), payload)

# Comments are html inside a json object
soup = BeautifulSoup(r.json()["comments_html"], "html.parser")

# Get raw text for every comment.
# The " ".join() strips out the newlines and tabs which are part of html
comments = [" ".join(s.text.split()) for s in soup.find_all("div", {"class" : "commentthread_comment_text"})]

calculateRep = lambda x:sum(["- +".index(i[0])-1for i in x.split('\n')if i[1:4]=="rep"])

print(calculateRep("\n".join(comments)))
\$\endgroup\$
2
  • \$\begingroup\$ if"rep"==i[1:4] for -1 \$\endgroup\$
    – ovs
    Apr 11, 2017 at 13:57
  • \$\begingroup\$ You don't need the square brackets \$\endgroup\$
    – ovs
    Apr 11, 2017 at 15:23
9
\$\begingroup\$

05AB1E, 18 16 17 bytes

Saved 2 bytes thanks to Okx
+1 byte due to change in spec where rep now need to be followed by a space.

|vy5£„+-S„·Ý «QÆO

Try it online!

Explanation

|v                   # for each line of input
  y5£                # get the first 4 chars of input
     „+-S„·Ý «       # push the list ['+rep ','-rep ']
              Q      # check each for equality
                     # results in either [1,0] for +rep, [0,1] for -rep or [0,0] for others
               Æ     # reduce by subtraction, gives either 1, -1 or 0
                O    # sum
\$\endgroup\$
12
  • \$\begingroup\$ You can replace ð¡0è with . I was working on a solution to this at the same time you were. \$\endgroup\$
    – Okx
    Apr 10, 2017 at 16:19
  • \$\begingroup\$ @Emigna I feel like my idea of |ðý#D'·Ý©.åÏ®1:O can be 14 or 15, I'm just not seeing it. Also stuck at 16, maybe it will help you though. I'll leave it here. Basically replacing the word "rep" with the number "1" so you can direct sum. \$\endgroup\$ Apr 10, 2017 at 17:03
  • \$\begingroup\$ @carusocomputing: I think I have it at 14 yes. Just gotta some more tests :) \$\endgroup\$
    – Emigna
    Apr 10, 2017 at 17:06
  • \$\begingroup\$ Better to beat the inevitable Jelly tie before it happens ;). \$\endgroup\$ Apr 10, 2017 at 17:08
  • \$\begingroup\$ @carusocomputing: actually my way 0|vy4£'·Ý1:R.V doesn't work for lines not starting with +/- rep. Back to the drawing board :( \$\endgroup\$
    – Emigna
    Apr 10, 2017 at 17:08
9
\$\begingroup\$

Perl 5, 25 bytes

24 bytes of code + -p flag.

$\+=/^\+rep /-/^-rep /}{

Try it online!

/^\+rep / returns 1 if the line starts with +rep; /^-rep / returns 1 if the line starts with -rep (so only one of them will be one at most). We use $\ to store the result, as it is implicitly printed at the end (thanks to -p flag and those unmatched }{).

\$\endgroup\$
3
  • \$\begingroup\$ Add two bytes because there needs to be a space after rep \$\endgroup\$ Apr 10, 2017 at 16:32
  • \$\begingroup\$ This doesn't seem very clear from the spec but since pretty much everyone is doing it, I'll edit that as soon as I get my hands on a computer. \$\endgroup\$
    – Dada
    Apr 10, 2017 at 16:44
  • \$\begingroup\$ I added it to the specs because the OP had left it as a comment \$\endgroup\$ Apr 10, 2017 at 16:46
6
\$\begingroup\$

Python 2, 54 bytes

q=('\n'+input()).count;print q('\n+rep ')-q('\n-rep ')

Try it online! Takes a multiline string as input.

Counts the appearances of '+rep ' and '-rep ' only at starts of lines by searching for the string following a newline symbol. To catch the first line, a newline is prepended to the input.

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

Retina, 63 51 50 49 bytes

Didn't quite comply with the spec so I fixed some issues but also golfed it a lot (by borrowing the first line from Kritixi Lithos's solution).

Saved another byte thanks to Kritixi Lithos.

ms`(?!^[+-]rep ).

+`\+-|-\+

(.)+
$1$.&
T`+
$^
0

Try it online!

Explanation

ms`(?!^[+-]rep ).

First, everything from the input is deleted, except for the + and - from any +rep or -rep at the start of a line.

+`\+-|-\+

Then adjacent pairs of + and - are removed until no more can be removed. After this, what's left is either a run of +s, a run of -s, or nothing.

(.)+
$1$.&

Then a run of one or more characters (either + or -) is replaced with the character making up the run followed by the length of the run. This way, + is preserved at the start for positive results and - for negatives.

T`+

Then all +s are removed, in the event that the rep is positive.

$^
0

Finally, if the string is empty at this point, the rep is 0, so we write 0.

\$\endgroup\$
1
  • \$\begingroup\$ You can do drop the and add a s (single-line mode) after the m on the first line \$\endgroup\$
    – user41805
    Apr 10, 2017 at 16:15
3
\$\begingroup\$

Mathematica, 47 bytes (ISO 8859-1 encoding)

(±c_:=StringCount["
"<>#,c];±"
+rep"-±"
-rep")&

Pure function taking a newline-separated string as input and returning an integer. Note that the three newlines in the code are flanked by quotes and are thus each equivalent to "\n" in a string (but this way is one byte shorter than "\n"). StringCount does the heavy lifting; we manually add a newline to the beginning of the string so that the first line matches when appropriate. ± is a unary helping function to avoid repetition of StringCount.

The alternative solution

(±c_:=StringCount["
"<>#,"
"<>c<>"rep"];±"+"-±"-")&

is 4 bytes longer, but I do like the sequence ±"+"-±"-"....

\$\endgroup\$
1
  • \$\begingroup\$ I think you might need to add a space behind the +/-rep as that was apparently part of the requirements \$\endgroup\$ Apr 10, 2017 at 17:09
3
\$\begingroup\$

Retina, 59 53 52 50 bytes

ms`(?!^[+-]rep ).

+`\+-|-\+

-+
-$.&
\++
$.&
^$
0

Try it online!

Check out Basic Sunset's shorter answer in the same language!

Explanation

ms`(?!^[+-]rep ).

Removes everything except for [+-]rep s.

+`\+-|-\+

Repeatedly removes 1 - for every + and vice versa.

-+
-$.&

Prepend a - (because the number is negative) to -s as well as replacing the -s with the number of -s.

\+
$.&

Do the same for +s, but don't prepend a -.

^$
0

Finally, if there is nothing, replace it with a 0.

\$\endgroup\$
2
3
\$\begingroup\$

PHP, 118 bytes

function s($a,$c=0){foreach(explode("
",$a)as$b){$b=substr($b,0,1).'1';if(is_numeric($b){$c+=$b});}return$c-($a=="");}

Try it online!

Used like this:

echo s("-rep bad
+rep good
+rep very good
+rep exceeds expectation");
\$\endgroup\$
3
  • \$\begingroup\$ This outputs 1 if you feed it the empty string \$\endgroup\$ Apr 10, 2017 at 16:30
  • \$\begingroup\$ @fəˈnɛtɪk fixed \$\endgroup\$
    – steenbergh
    Apr 10, 2017 at 16:47
  • \$\begingroup\$ Would recommend fixing your link. It also errors after outputting if you give it a non +/-rep line :P \$\endgroup\$ Apr 10, 2017 at 16:51
3
\$\begingroup\$

Röda, 53 bytes

{{|l|[1]if[l=~`\+rep .*`];[-1]if[l=~`-rep .*`]}_|sum}

Try it online!

\$\endgroup\$
0
3
\$\begingroup\$

JavaScript, 55 bytes

Thanks @Neil for golfing off 12 bytes Thanks @Arnauld for golfing off 2 bytes

x=>x.split(/^\+rep /m).length-x.split(/^-rep /m).length

Try it online!

var y=x=>(x.match(/^\+rep /gm)||'').length-(x.match(/^-rep /gm)||'').length

document.querySelector('div').innerText=y(document.querySelector('textarea').value)
textarea{
  width: 95%;height: 100px;
  }
<textarea oninput = "document.querySelector('div').innerText=y(this.value)">
-rep Cheater!!
+rep very good, fun to play with
+rep my friend +rep
good
</textarea>
<div></div>

\$\endgroup\$
1
  • \$\begingroup\$ Save 12 bytes by using split instead of match (it always returns an array which is 1 longer that you normally want but the two 1s cancel). I also tried to eliminate the duplication but it came out at 57 bytes again. \$\endgroup\$
    – Neil
    Apr 11, 2017 at 0:41
1
\$\begingroup\$

Java, 109 bytes

l->{int i=0;for(String s:l.split("\n")){if(s.startsWith("+rep "))i++;if(s.startsWith("-rep "))i--;}return i;}

Trying to make this shorter using Stream's

\$\endgroup\$
1
  • \$\begingroup\$ Needs a space after rep \$\endgroup\$ Apr 10, 2017 at 17:59
1
\$\begingroup\$

Stacked, 45 bytes

'^([+-])rep |.'{.a:''['#'a+]a if}mrepl'0'\+#~

Try it online!

Alternatively (49 bytes):

lines'^[-+]rep 'match$#'YES[0#0# '#'\+]"!''#`0\#~

Explanation

'^([+-])rep |.'{.a:''['#'a+]a if}mrepl'0'\+#~

This basically extracts all + or - attached to the beginning of the line and rep. Then, to each, it prepends a #. Then, to the entire thing, a 0 is prepended. #~ evaluates the string, which now looks something like:

0#+#+#-

#+ is increment and #- is decrement. Thus, we obtain our desired result.

\$\endgroup\$
1
\$\begingroup\$

Retina, 38 bytes

M!m`^[+-]rep 
Os`.
+`\+-

*\M1!`-
[+-]

Try it online!

A different (and shorter) solution than the ones already posted in Retina.

Explanation

M!m`^[+-]rep 

(This line has a trailing space). Keep only the relevant parts of the input, i.e. the +rep or -rep at the beginning of a line.

Os`.

Sort all characters (including newlines). this will put +s and -s next to each other.

+`\+-

Repeatedly remove +- couples until at most one of the two signs remains.

*\M1!`-

Match the first - (if present) and print it without modifying the string.

[+-]

Count the number of signs remaining, and print it since this is the final stage of the program.

\$\endgroup\$
0
\$\begingroup\$

C#, 87 bytes

s=>{int n=0;foreach(var t in s.Split('\n'))n+=t.IndexOf("rep ")==1?44-t[0]:0;return n;}

Anonymous function which splits the input string by using the newline character, searches for the "rep " string prefixed by a character and, if it finds it, increments the reputation (the n variable) by 1 or -1.

Full program with ungolfed method and test cases:

using System;

class P
{
    static void Main()
    {
        Func<string, int> f =
        s=>
        {
            int n = 0;
            foreach (var t in s.Split('\n'))
                n += t.IndexOf("rep ") == 1 ?
                    44 - t[0]
                    :
                    0;
            
            return n;
        };
        
        // test cases:
        Console.WriteLine(f(@"+rep fast trade
+rep nice person
-rep too good"));       // 1

        Console.WriteLine(f(@"-rep hacker
-rep scammer
-rep was mean"));       // -3

        Console.WriteLine(f(@"first
i don't like him
+rep good at cs go"));  // 1

        Console.WriteLine(f(@"+rep +rep
hi +rep
-rep"));            // 1
        
        Console.WriteLine(f(@"+ rep"));     // 0

        Console.WriteLine(f(@"+rep like
-thing"));          // 1
    }
}

Note that the ASCII code for + is 43 and for - is 45. This method passes all test cases from the OP. However, if the first character is something else, this will lead to wrong answers!

This can be fixed at the cost of 17 bytes:

C# fixed, 104 bytes

s=>{int n=0;foreach(var t in s.Split('\n'))n+=t.IndexOf("rep ")==1?t[0]==43?1:t[0]==45?-1:0:0;return n;}

The modified anonymous function will check for a + or - sign as the first character in each line.

\$\endgroup\$
0
\$\begingroup\$

Japt, 14 bytes

r`œp`1 f".%d 

Try it online!

+1 byte for -x flag

\$\endgroup\$
0
\$\begingroup\$

C++, 144 bytes

#import<iostream>
int f(){int r=0;for(std::string s;std::getline(std::cin,s);)if((s[0]==43|s[0]==45)&s.substr(1,4)=="rep ")r-=s[0]-44;return r;}

Try it online!

\$\endgroup\$
1
0
\$\begingroup\$

C#, 104 bytes


Despite existing already one solution -- and mine being longer -- I still think I should post it, since the on already here might fail if something like '=rep ' gets in it's way.


Golfed

i=>{var c=0;foreach(var o in i.Split('\n'))c+=o.IndexOf("rep ")!=1?0:o[0]==43?1:o[0]==45?-1:0;return c;}

Ungolfed

i => {
   var c = 0;
   
   foreach( var o in i.Split( '\n' ) )
      c += o.IndexOf( "rep " ) != 1
         ? 0
         : o[ 0 ] == 43
            ? 1
            : o[ 0 ] == 45
               ? -1
               : 0;
   
   return c;
}

Ungolfed readable

i => {
   // Counter for the 'reputation'
   var c = 0;
   
   // Cycle through every line
   foreach( var o in i.Split( '\n' ) )
      // Check if the "rep " string has index 1
      //   ( Index 0 should be the sign )
      c += o.IndexOf( "rep " ) != 1
         // Add 0 if the rep isn't on the right position
         ? 0
         // Check for the '+' sign
         : o[ 0 ] == 43
            // Add 1 if the sign is found
            ? 1
            // Check for the '-' sign
            : o[ 0 ] == 45
               // Add -1 if the sign is found
               ? -1
               // Add 0 if another char is found
               : 0;
   
   // Return the 'reputation'
   return c;
}

Full code

using System;
using System.Collections.Generic;

namespace Namespace {
   class Program {
      static void Main( String[] args ) {
         Func<String, Int32> f = i => {
            var c = 0;

            foreach( var o in i.Split( '\n' ) )
               c += o.IndexOf( "rep " ) != 1
               ? 0
                  : o[ 0 ] == 43
                  ? 1
                  : o[ 0 ] == 45
                     ? -1
                     : 0;

            return c;
         };

         List<String>
            testCases = new List<String>() {
               @"+rep fast trade
+rep nice person
-rep too good",
               @"-rep hacker
-rep scammer
-rep was mean",
               @"first
i don't like him
+rep good at cs go",
               @"+rep +rep
hi +rep
-rep",
               @"+ rep",
               @"+rep like
-thing",
         };

         foreach( String testCase in testCases ) {
            Console.WriteLine( $"{testCase}\n{f( testCase )}\n" );
         }

         Console.ReadLine();
      }
   }
}

Releases

  • v1.0 - 104 bytes - Initial solution.

Notes

Nothing to add

\$\endgroup\$
0
\$\begingroup\$

Ruby, 46 bytes

->x{rep=1;eval ?0+x.map{|a|a[/^[+-]rep /]}*''}

Get all the +/-rep from input, and put together in a single string. Then evaluate that for rep=1.

\$\endgroup\$
0
\$\begingroup\$

JavaScript ES6, 85 79 bytes

l=>eval(l.split`
`.map(i=>(r=i.slice(0,5))==`+rep `?1:r==`-rep `?-1:0).join`+`)

Try it

f=l=>eval(l.split`
`.map(i=>(r=i.slice(0,5))==`+rep `?1:r==`-rep `?-1:0).join`+`);

console.log(f(`+rep fast trade
+rep nice person
-rep too good`));

console.log(f(`-rep hacker
-rep scammer
-rep was mean`));

console.log(f(`first
i don't like him
+rep good at cs go`));

console.log(f(`+rep +rep
hi +rep
-rep`));

console.log(f(`+ rep`));

console.log(f(`+rep like
-thing`));


Ungolfed

const repcount=list=>{
    let array=list.split("\n");
    let values=array.map(item=>{
        let rep=item.slice(0,5);
        return rep==="+rep "?1:rep==="-rep "?-1:0;
    });
    let result=values.reduce((a,b)=>a+b);
    return result;
};

History

85 bytes

l=>l.split`\n`.map(i=>(r=i.slice(0,5))=="+rep "?1:r=="-rep "?-1:0).reduce((a,b)=>a+b)
\$\endgroup\$

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