Dis-moi combien de problèmes de mathématiques je dois faire!

36

Mon professeur me donne toujours les problèmes de mathématiques les plus compliqués à faire à la maison. Comme:pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even . Et je veux savoir à l'avance combien de temps il me reste à consacrer à mes devoirs, mais je ne veux pas avoir à comprendre tout cela. C'est pourquoi c'est à vous de le programmer pour moi.

Caractéristiques

  • Vous obtiendrez une chaîne détaillant les problèmes que je dois résoudre comme arguments, stdio, etc.
  • Ils seront séparés par une virgule (éventuellement comma-spaceséparés)
  • Cela inclura des problèmes simples sous la forme d’un nombre (par exemple 79)
  • Et va dans la forme 17-18(encore une fois, vous devez traiter des espaces optionnels)
  • Les gammes incluent les deux extrémités
  • Les gammes seront éventuellement complétées par oddou even, à prendre en compte.
  • Un ensemble de plages / pages sera précédé d’un numéro de page sous la forme pg. 545: , devant à nouveau traiter d'espaces facultatifs. Vous pouvez les ignorer en toute sécurité, car vous devez résoudre les problèmes sur toutes les pages.
  • Le texte peut être en majuscule ou en minuscule, mais ne sera pas les deux.
  • Retour, stdout, etc. le nombre de problèmes que je dois faire pour faire mes devoirs.
  • Puisqu'il s'agit de , le code le plus court en octets gagne!

Cas de test

pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even   ->    27
pg. 34: 1                                                    ->    1
PG. 565: 2-5,PG.345:7                                        ->    5
pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80                ->    70
pg.492: 2-4 odd,7-9 even                                     ->    2
Maltysen
la source
12
Le professeur peut vous donner une gamme de 2-4 odd? Cela semble poser quelques problèmes pour des approches plus simples.
Björn Lindqvist le
1
^ Je pense que cela devrait être un cas test, selon l'énoncé du problème actuel.
mbomb007
2
Il devrait y avoir ce cas de test:pg.492: 2-4 odd,7-9 even -> 2
mbomb007
2
Les gammes peuvent-elles se chevaucher? Par exemple 22-26,25-30?
Reto Koradi
1
@RetoKoradi no.
Maltysen

Réponses:

15

CJam, 61 58 51 48 46 43 41 38 octets

leuS-',/{':/W>:~_2*2<~z),>1f&\,5--~}%,

Vérifiez les cas de test dans l' interpréteur CJam .

Comment ça marche

leuS-      e# Read a line from STDIN, convert to uppercase and remove spaces.
',/        e# Split at commas.
{          e# For each chunk:
  ':/W>    e#   Split at colons and only keep the last chunk.
  :~       e#   Evaluate the string inside the array.
  _2*      e#   Copy the array, repeated twice.
  2<       e#   Keep only the first two elements.

           e#   In all possible cases, the array now contains exactly two
           e#   integers, which are equal in case of a single problem.

  ~        e#   Dump the array on the stack.
  z),      e#   Push [0 ... -N], where N is the second integer.
  >        e#   Discard the first M elements, where M is the first integer.
  1f&      e#   Replace each element by its parity.
  \,       e#   Push L, the length of the original array.

           e#   EVEN and ODD all push elements, so L is 1 for single problems,
           e#   2 for simple ranges, 5 for odd ranges and 6 for even ranges.

  5--      e#   Discard all elements equal to L - 5 from the array of parities.

           e#   This removes 0's for odd ranges, 1's for even ranges, -3's for
           e#   other ranges and -4's for single problems, thus counting only
           e#   problems of the desired parities.

  ~        e#   Dump the resulting array on the stack.
}%         e# Collect the results in an array.
,          e# Compute its length.
Dennis
la source
Est-ce que cela fonctionne avec le dernier cas de test?
mbomb007
Cela fait. J'ai ajouté le dernier cas de test au lien.
Dennis
10

Perl - 47 octets

#!perl -p054
{map$\+=($_%2x9^lc$')!~T,$&..$'*/\d+ ?-/}}{

Modifié pour réussir le nouveau test.


Original

Perl - 36 octets

#!perl -p054
$\+=/\d+ ?-/*($'-$&>>/o|e/i)+1}{

En comptant le shebang comme 4, l'entrée est prise de stdin.


Exemple d'utilisation

$ echo pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even | perl math-problems.pl
27

$ echo pg. 34: 1 | perl math-problems.pl
1

$ echo PG. 565: 2-5,PG.345:7 | perl math-problems.pl
5

$ echo pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80 | perl math-problems.pl
70

Mises en garde

Pour les plages paires / impaires, au moins un des points d'extrémité doit correspondre à la parité de la plage. Par exemple, 11-19 odd, 11-20 oddet 10-19 oddseront tous correctement comptés comme 5, mais 10-20 oddsera plus compté comme 6.

primo
la source
Comment ça marche pg. 20: 13-15 even? ou pg. 20: 13-14 even?
Pas que Charles
1
*est un caractère plus court que &&pour une amélioration facile:$\+=/\d+ ?-/*($'-$&>>/o|e/i)+1for@F}{
Grimmy
1
Mec, c'est malin! À moins que je manque quelque chose, vous devriez être capable d'éliminer lc=~.
Dennis
1
J'ai eu cette T^partie, mais quelque part a manqué cela a lcchangé le cas de $'. Préfixer lcà $'aurait été légèrement plus courte. Cela devrait toujours fonctionner pour l'une lc$'!~(T^lc$_%2)ou l' autre approche: ou($_%2x9^lc$')!~T
Dennis
1
@Dennis pour la version précédente, il aurait fallu des parenthèses. !~TC'est génial, merci!
Primo
6

Python 2, 259 253 249 239 octets

Essayez-le ici

Cela peut probablement encore être joué au golf plus.

Edit: Correction d'un bug qui faisait que le mien ne fonctionnait pas 2-4 evencomme prévu. Puis effectué un ajustement pour ce correctif. Ce correctif m'a sauvé quatre octets!

Edit: Now utilise input()et +2 octets pour les deux guillemets , l'utilisateur doit entourer l' entrée avec.

import re
c=0
for x in re.sub(r'..\..*?:','',input()).replace(' ','').split(','):
 y=x.split('-')
 if len(y)<2:c+=1
 else:
    a,b=y[0],y[1];d=int(re.sub('[A-z]','',b))-int(a)+1
    if b[-1]>':':d=d/2+d%2*(int(a)%2==ord(b[-3])%2)
    c+=d
print c

Moins joué au golf (avec commentaires!: D):

J'espère que ces commentaires aident certains. Je ne suis toujours pas sûr d'avoir expliqué correctement ou non cette dernière ligne complexe.

import re
def f(s):
    c=0
    l=re.sub(r'..\..*?:','',s).replace(' ','').split(',')   # remove pg #'s and split
    for x in l:
        y=x.split('-')
        if len(y)<2:                                # if not a range of numbers
            c+=1
        else:
            a,b=y[0],y[1]                           # first and second numbers in range
            d=int(re.sub('[A-z]','',b))-int(a)+1    # number of pages
            if b[-1]>':':                           # if last character is not a digit
                # half the range
                # plus 1 if odd # of pages, but only if first and last numbers in the range
                #       are the same parity
                # ord(b[-3])%2 is 0 for even (v), 1 for odd (o)
                d=d/2+(d%2)*(int(a)%2==ord(b[-3])%2)
            c+=d
    print c
mbomb007
la source
2
Just a little thing, since you are using Python 2, you can use spaces and tabs (1 byte each) as different indents. Relevant tip
FryAmTheEggman
Also found I had the count wrong at first. Copying tabs from the editors converts them to spaces.
mbomb007
You can save at least 4 bytes by doing s=raw_input() and removing some indentation.
4

Pyth, 43 42 44 42 bytes

lsm-%R2}hKvMc-ecd\:G\-eK?}\ed}edGYc-rzZd\,

Try it online: Demonstration or Test harness

I think I can still chop one or two bytes.

Explanation

lsm-%R2}hKvMc-ecd\:G\-eK?}\ed}edGYc-rzZd\,  implicit: z = input string
                                    rzZ     convert z to lower-case
                                   -   d    remove all spaces from z
                                  c     \,  and split by ","
  m                                         map each part d to:
               cd\:                           split d by ":"
              e                               and only use the last part (removes page number)
             -     G                          remove all letters (removes odd/even)
            c       \-                        split by "-"
          vM                                  and evaluate all (one or two) numbers
         K                                    and store the result in K
       }hK            eK                      create the list [K[0], K[0]+1, ..., K[-1]]
    %R2                                       apply modulo 2 to each element
   -                                          and remove:
                         }\ed                   "e" in d (1 for in, 0 for not in)
                        ?    }edG               if d[-1] in "abcde...z" else
                                 Y              dummy value
 s                                            combine all the lists
l                                             print the length                                      
Jakube
la source
Does this work with the newest test case?
mbomb007
@mbomb007: It does.
Dennis
3

JavaScript (Spidermonkey console) - 139

It's just easier to test on the command line.

for(r=/[:,] *(\d+)[- ]*(\d+)? *(o|e)?/gi,m=readline(z=0);f=r.exec(m);z+=!b||((p=b-a)%2||!c|a%2^/e/i.test(c))+p/(2-!c)|0)[,a,b,c]=f
print(z)

Ungolfed:

// any number set after "pg:" or a comma
// \1 is FROM, \2 is TO, \3 is odd/even 
r=/[:,] *(\d+)[- ]*(\d+)? *(o|e)?/gi;
m=readline();
z=0; // this is the sum.
while(f=r.exec(m)){
    [,from,to,oddEven]=f;
    if(!to) {
        z++;
    } else {
        if((to-from)%2) {
            // if to and from are not the same parity, add 1
            z++;
        } else {
            // if to and from are not the same parity...
            if(!oddEven) {
                // and we don't have a parity marker, add one
                z++;
            } else if(a%2 != /e/i.test(c)) {
                // if we do have a parity marker,
                // AND the parity of from and to matches the 
                // parity of the oddEven sign, then add 1
                z++;
            }
        }
        // then add the difference between to-from and
        // if oddEven exists, divide by two and round down
        z+=(to-from)/(oddEven?2:1)|0;
    }

}
print(z);
Not that Charles
la source
Can [,from,to] just simply be [from,to]?
Yytsi
1
@TuukkaX no because that is to discard the first value of the array from r.exec, which contains the entire matched string.
Patrick Roberts
3

Factor - 488 bytes:

USING: arrays ascii kernel math math.parser math.ranges pcre sequences ;
IN: examples.golf.homework

: c ( a -- b )
    >lower "(?:[,:]|^) *(\\d+) *(?:- *(\\d+) *(e|o)?)?" findall [
        rest [ second dup string>number swap or ] map
        dup length 1 = [ drop 1 ] [
            dup length 2 = [ first2 swap - 1 + ] [
                first3 "o" = [ [a,b] [ odd? ] count ] [
                    [a,b] [ even? ] count
                ] if
            ] if
        ] if
    ] map sum ;
Björn Lindqvist
la source
2

Bash 344 315 306 294 262 252 242 240

IFS=,
o(){ R=0;for ((i=$1;i<=$2;R+=i++%2));do :
done
}
e(){ q=$R;o $*;((R=q-R))
}
for c in ${1,,};do
c=${c#*:}
m=${c##* }
l=${c%-*}
l=${l// }
h=${c#*-}
[[ a< $m ]]&&h=${h% *}
h=${h// }
((R=h-l+1))
eval "${m::1} $l $h"
((t+=R))
done;echo $t

I don't think I've golfed this as much as is possible but not bad for a first submission. Commented version below.

IFS=, # Setup IFS for the for loops, We want to be able to split on commas

o(){ # Odd
    R=0  # Reset the R variable

    # Increments R for each odd element in the range
    # $1-$2 inclusive
    for ((i=$1;i<=$2;R+=i++%2));do
        : # Noop command
    done
}

e(){ # Even
    # Save R, it contains the total number of elements between low
    # and high
    q=$R
    # Call Odd, This will set R
    o $*
    # Set R = total number of elements in sequence - number of odd elements.
    ((R=q-R))
}

# This lowercases the firs arg. IFS causes it to split on commas.
for c in ${1,,};do
    c=${c#*:}  # Strips the page prefix if it exists
    m=${c##* }  # Capture the odd/even suffix if it exists
    l=${c%-*}  # Capture low end of a range, Strips hyphen and anything after it
    l=${l// }  # Strips spaces
    h=${c#*-}  # Capture high end of a range, Strips up to and including hyphen

    # If we have captured odd/even in m this will trigger and strip
    # it from the high range variable.
    [[ a< $m ]]&&h=${h% *}
    h=${h// }  # Strip Spaces

    # Give R a value.
    # If we are in a range it will be the number of elements in that range.
    # If we arent l and h will be equal are R will be 1
    ((R=h-l+1))

    # Call the odd or even functions if we captured one of them in m.
    # If we didnt m will contain a number and this will cause a warning
    # to stderr but it still works.
    eval "${m::1} $l $h"

    # Add R to total
    ((t+=R))
done

# Print result
echo $t

Run the test cases:

bash math.sh "pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even"
bash math.sh "pg. 34: 1"
bash math.sh "PG. 565: 2-5,PG.345:7"
bash math.sh "pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80"
bash math.sh "pg.492: 2-4 odd,7-9 even"

Depending on how I read the rules it could be possible to save another 4 bytes. If even/odd is always lowercase ${1,,} can be changed to $1

Daniel Wakefield
la source
Does this work with the newest test case?
mbomb007
Just tested it and yes it does.
Daniel Wakefield
1

JavaScript (ES6), 149

Run snippet in Firefox to test

F=s=>s.replace(/([-,.:]) *(\d+) *(o?)(e?)/ig,(_,c,v,o,e)=>
  c=='-'?(t+=1+(o?(v-(r|1))>>1:e?(v-(-~r&~1))>>1:v-r),r=0)
  :c!='.'&&(t+=!!r,r=v)
,r=t=0)&&t+!!r

// Less golfed

U=s=>{
  var r = 0, // value, maybe range start
  t = 0; // total
  s.replace(/([-,.:]) *(\d+) *(o?)(e?)/ig, // execute function for each match
    (_ // full match, not used
     , c // separator char, match -:,.
     , v // numeric value
     , o // match first letter of ODD if present
     , e // match first letter of EVEN if present
    )=>
    {
      if (c == '-') // range end
      {
        t++; // in general, count range values as end - start + 1
        if (o) // found 'odd'
        {
          r = r | 1; // if range start is even, increment to next odd
          t += (v-r)>>1; // end - start / 2
        }
        else if (e) // found 'even'
        {
          r = (r+1) & ~1; // if range start is odd, increment to next even
          t += (v-r)>>1; // end - start / 2
        }
        else
        {
          t += v-r; // end - start
        }
        r = 0; // range start value was used
      }
      else if (c != '.') // ignore page numbers starting with '.'
      { 
        // if a range start was already saved, then it was a single value, count it
        if (r != 0) ++t;
        r = v; // save value as it counld be a range start
      }
    }
  )            
  if (r != 0) ++t; // unused, pending range start, was a single value
  return t
}

// TEST

out=x=>O.innerHTML+=x+'\n';

test=["pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even",
"pg. 34: 1", "PG. 565: 2-5,PG.345:7",
"pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80"];

test.forEach(t=>out(t + ' --> ' + F(t)))
<pre id=O></pre>

edc65
la source
1

C++ 226 224 222

I know I'm kinda late for the party, but this seemed like a fun problem and lack of entries using C-family languages bothered me.

So here's a C++ function using no regexp or string substitution, just some simple math:

void f(){char c;int o=0,i,j;while(cin>>c)c=='p'||c==80?cin.ignore(9,58):cin.unget(),cin>>i>>c&&c==45?cin>>j>>c&&(c=='e'||c=='o')?cin.ignore(9,44),c=='e'?i+=i&1,j+=!(j&1):(i+=!(i&1),j+=j&1),o+=(j-i)/2:o+=j-i:0,++o;cout<<o;}

Ungolfed:

void f()
{
  char c;
  int o=0,i,j;
  while(cin>>c)
    c=='p'||c==80?cin.ignore(9,58):cin.unget(),
    cin>>i>>c&&c==45?
      cin>>j>>c&&(c=='e'||c=='o')?
        cin.ignore(9,44),
        c=='e'?
          i+=i&1,j+=!(j&1)
        :(i+=!(i&1),j+=j&1),
        o+=(j-i)/2
      :o+=j-i
    :0,
    ++o;
  cout<<o;
}

I didn't say it would be readable, now did I? :) Ternary operators are hell. I tried my best to (sort of) format it, though, so I hope it helps at least a little bit.

Usage:

#include <iostream>
using namespace std;

void f(){char c;int o=0,i,j;while(cin>>c)c=='p'||c==80?cin.ignore(9,58):cin.unget(),cin>>i>>c&&c==45?cin>>j>>c&&(c=='e'||c=='o')?cin.ignore(9,44),c=='e'?i+=i&1,j+=!(j&1):(i+=!(i&1),j+=j&1),o+=(j-i)/2:o+=j-i:0,++o;cout<<o;}

int main()
{
  f();
}
Alexander Revo
la source
207 bytes
ceilingcat
0

Python 2 - 163 bytes:

Try it here

Input must be given inside quotes

import re
print len(eval(re.sub('([^,]+:|) *(\d+) *-? *(\d*)(?=.(.)).*?,',r'[x for x in range(\2,\3+1 if \3.0 else \2+1)if x%2!="oe".find("\4")]+',input()+',[]')))

Explanation:

The general approach is to convert the existing input into valid python, then evaluate this. Each comma separated value is converted to an array, which are then all appended together and the length gives the final result.

For example, with the input 12-15 odd,19, before evaluation the regex substitution will produce:

[x for x in range(12,15+1 if 15.0 else 12+1)if x%2!="oe".find("o")]
+[x for x in range(19,+1 if .0 else 19+1)if x%2!="oe".find("[")]
+[]

To break this down further:

  • 15+1 if 15.0 else 12+1 This bit will make sure the second argument of range() is correct depending if there is a range or a single value given (if \3 is empty, \3.0 will evaluate to false).
  • if x%2!="oe".find("o") Depending on the value found two characters away from the final digit in the range ((?=.(.)) in the regex - lookahead two characters without consuming them), there are three possible outcomes:

    • x%2!="oe".find("o") evaluates to x % 2 != 0 (only odd matched)
    • x%2!="oe".find("e") evaluates to x % 2 != 1 (only even matched)
    • x%2!="oe".find("[") evaluates to x % 2 != -1 (this character could be multiple things as it's just two characters away from the last digit, but will only be o or e if odd/even is intended)
  • The seemingly random +[] on the end is to ensure that the last token in the comma-separated list has a character two away from the last digit, but also allows us to append something to the end to use up the last '+' which would have been trailing otherwise.
Jarmex
la source