Оцените игру в кости, прокручивающую строки нотации

int size = (*array).size();

Он не скажет вам размер array, он скажет вам длину первой строки в этом массиве, вы должны передать длину массива функции отдельно. Функция должна выглядеть следующим образом:

bool in_array(string value, string *array, int length)

& nbsp;

Но лучшим выбором будет использование std::vector и std::find:

bool in_array(const std::string &value, const std::vector<string> &array)
{
    return std::find(array.begin(), array.end(), value) != array.end();
}

, а затем вы можно использовать как:

int main() {
    std::vector<std::string> tab {"sdasd", "sdsdasd"};

    if (in_array(n, tab)) {
        ...
    }
}
21
задан 17 revs, 5 users 81% 19 July 2017 в 12:54
поделиться

13 ответов

Python , 452 байта в сжатой версии

Я не уверен, круто ли это, уродливо или просто глупо, но писать это было весело.

Мы делаем следующее: мы используем регулярные выражения (которые обычно не подходят для такого рода вещей) для преобразования строки нотации игральных костей в список команд на небольшом языке, основанном на стеке. В этом языке есть четыре команды:

  • mul умножает два верхних числа в стеке и помещает результат
  • add складывает два верхних числа в стеке и сдвигает результат
  • roll извлекает размер игральных костей из стека, затем подсчитывает, бросает кубики с разным размером, подсчитывает количество раз и помещает результат
  • число просто помещает себя в стек

Этот список команд затем оценивается.

import re, random

def dice_eval(s):
    s = s.replace(" ","")
    s = re.sub(r"(\d+|[d+*])",r"\1 ",s) #seperate tokens by spaces
    s = re.sub(r"(^|[+*] )d",r"\g<1>1 d",s) #e.g. change d 6 to 1 d 6
    while "*" in s:
        s = re.sub(r"([^+]+) \* ([^+]+)",r"\1 \2mul ",s,1)
    while "+" in s:
        s = re.sub(r"(.+) \+ (.+)",r"\1 \2add ",s,1)
    s = re.sub(r"d (\d+) ",r"\1 roll ",s)

    stack = []

    for token in s.split():
        if token == "mul":
            stack.append(stack.pop() * stack.pop())
        elif token == "add":
            stack.append(stack.pop() + stack.pop())
        elif token == "roll":
            v = 0
            dice = stack.pop()
            for i in xrange(stack.pop()):
                v += random.randint(1,dice)
            stack.append(v)
        elif token.isdigit():
            stack.append(int(token))
        else:
            raise ValueError

    assert len(stack) == 1

    return stack.pop() 

print dice_eval("2*d12+3d20*3+d6")

Кстати (это обсуждалось в комментариях к вопросу), эта реализация позволит использовать такие строки, как «2d3d6» , понимая это как «бросьте d3 дважды, затем бросьте d6 столько раз, сколько будет результат двух бросков».

Также, хотя есть некоторые при проверке ошибок, он по-прежнему ожидает правильного ввода. Например, передача «* 4» приведет к бесконечному циклу.

Вот сжатая версия (некрасивая):

import re, random
r=re.sub
def e(s):
 s=r(" ","",s)
 s=r(r"(\d+|[d+*])",r"\1 ",s)
 s=r(r"(^|[+*] )d",r"\g<1>1 d",s)
 while"*"in s:s=r(r"([^+]+) \* ([^+]+)",r"\1 \2M ",s)
 while"+"in s:s=r(r"(.+) \+ (.+)",r"\1 \2A ",s)
 s=r(r"d (\d+)",r"\1 R",s)
 t=[]
 a=t.append
 p=t.pop
 for k in s.split():
  if k=="M":a(p()*p())
  elif k=="A":a(p()+p())
  elif k=="R":
   v=0
   d=p()
   for i in [[]]*p():v+=random.randint(1,d)
   a(v)
  else:a(int(k))
 return p()
1
ответ дан 29 November 2019 в 20:09
поделиться

Решение JavaScript , 340 символов при сжатии (без eval, поддерживает префиксный мультипликатор и суффиксное сложение):

function comp (s, m, n, f, a) {
    m = parseInt( m );
    if( isNaN( m ) ) m = 1;
    n = parseInt( n );
    if( isNaN( n ) ) n = 1;
    f = parseInt( f );
    a = typeof(a) == 'string' ? parseInt( a.replace(/\s/g, '') ) : 0;
    if( isNaN( a ) ) a = 0;
    var r = 0;
    for( var i=0; i<n; i++ )
        r += Math.floor( Math.random() * f );
    return r * m + a;
};
function parse( de ) {
    return comp.apply( this, de.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i) );
}

Тестовый код:

var test = ["3d6 + 12", "4*d12 + 3", "d100"];
for(var i in test)
    alert( test[i] + ": " + parse(test[i]) );

Сжатая версия (уверен, что вы можете сделать короче ):

function c(s,m,n,f,a){m=parseInt(m);if(isNaN(m))m=1;n=parseInt(n);if(isNaN(n))n=1;f=parseInt(f);a=typeof(a)=='string'?parseInt(a.replace(/\s/g,'')):0;if(isNaN(a))a=0;var r=0;for(var i=0;i<n;i++)r+=Math.floor(Math.random()*f);return r*m+a;};function p(d){return c.apply(this,d.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i));}
4
ответ дан 29 November 2019 в 20:09
поделиться

Класс C #. Он выполняет рекурсивную оценку для сложения и умножения слева направо для цепных бросков кубиков

Редактирование:

  • Удалено . Заменить ("", "") при каждом вызове
  • Добавлено ] .Trim () на int.TryParse вместо
  • Теперь вся работа выполняется одним методом
  • Если количество граней не указано, предполагается 6 (см. Статью в Wiki)
  • Отредактирован избыточный вызов для анализа левой части "d"
  • Отредактирован ненужный оператор if

Минимизированный: (411 байт)

class D{Random r=new Random();public int R(string s){int t=0;var a=s.Split('+');if(a.Count()>1)foreach(var b in a)t+=R(b);else{var m=a[0].Split('*');if(m.Count()>1){t=1;foreach(var n in m)t*=R(n);}else{var d=m[0].Split('d');if(!int.TryParse(d[0].Trim(),out t))t=0;int f;for(int i=1;i<d.Count();i++){if(!int.TryParse(d[i].Trim(),out f))f=6;int u=0;for(int j=0;j<(t== 0?1:t);j++)u+=r.Next(1,f);t+=u;}}}return t;}}

Расширенная форма:

    class D
    {
        /// <summary>Our Random object.  Make it a first-class citizen so that it produces truly *random* results</summary>
        Random r = new Random();

        /// <summary>Roll</summary>
        /// <param name="s">string to be evaluated</param>
        /// <returns>result of evaluated string</returns>
        public int R(string s)
        {
            int t = 0;

            // Addition is lowest order of precedence
            var a = s.Split('+');

            // Add results of each group
            if (a.Count() > 1)
                foreach (var b in a)
                    t += R(b);
            else
            {
                // Multiplication is next order of precedence
                var m = a[0].Split('*');

                // Multiply results of each group
                if (m.Count() > 1)
                {
                    t = 1; // So that we don't zero-out our results...

                    foreach (var n in m)
                        t *= R(n);
                }
                else
                {
                    // Die definition is our highest order of precedence
                    var d = m[0].Split('d');

                    // This operand will be our die count, static digits, or else something we don't understand
                    if (!int.TryParse(d[0].Trim(), out t))
                        t = 0;

                    int f;

                    // Multiple definitions ("2d6d8") iterate through left-to-right: (2d6)d8
                    for (int i = 1; i < d.Count(); i++)
                    {
                        // If we don't have a right side (face count), assume 6
                        if (!int.TryParse(d[i].Trim(), out f))
                            f = 6;

                        int u = 0;

                        // If we don't have a die count, use 1
                        for (int j = 0; j < (t == 0 ? 1 : t); j++)
                            u += r.Next(1, f);

                        t += u;
                    }
                }
            }

            return t;
        }
    }

Контрольные примеры:

    static void Main(string[] args)
    {
        var t = new List<string>();
        t.Add("2d6");
        t.Add("2d6d6");
        t.Add("2d8d6 + 4d12*3d20");
        t.Add("4d12");
        t.Add("4*d12");
        t.Add("4d"); // Rolls 4 d6

        D d = new D();
        foreach (var s in t)
            Console.WriteLine(string.Format("{0}\t{1}", d.R(s), s));
    }
13
ответ дан 29 November 2019 в 20:09
поделиться

PHP , 147 символов, нет eval:

preg_match('/(\d+)?d(\d+)[\s+]?([\+\*])?[\s+]?(\d+)?/',$i,$a);$d=rand(1,$a[2])*((!$a[1])?1:$a[1]);$e['+']=$d+$a[4];$e['*']=$d*$a[4];print$e[$a[3]];

$ i содержит входную строку.

Edit: ой, забыл о операции с префиксом. brb.

0
ответ дан 29 November 2019 в 20:09
поделиться

Ruby, 87 символов, использует eval

Вот мое решение Ruby, частично основанное на OP. Он на пять символов короче и использует eval только один раз.

def f s
eval s.gsub(/(\d+)?[dD](\d+)/){n=$1?$1.to_i: 1;n.times{n+=rand $2.to_i};n}
end

Читаемая версия кода:

def f s
    eval (s.gsub /(\d+)?[dD](\d+)/ do
        n = $1 ? $1.to_i : 1
        n.times { n += rand $2.to_i }
        n
    end)
end
1
ответ дан 29 November 2019 в 20:09
поделиться

Ruby , 166 символов, нет eval

На мой взгляд, довольно элегантно;).

def g s,o=%w{\+ \* d}
o[a=0]?s[/#{p=o.pop}/]?g(s.sub(/(\d+)?\s*(#{p})\s*(\d+)/i){c=$3.to_i
o[1]?($1||1).to_i.times{a+=rand c}+a:$1.to_i.send($2,c)},o<<p):g(s,o):s
end

Деобфусцированная версия + комментарии:

def evaluate(string, opers = ["\\+","\\*","d"])
  if opers.empty?
    string
  else
    if string.scan(opers.last[/.$/]).empty? # check if string contains last element of opers array

      # Proceed to next operator from opers array.

      opers.pop
      evaluate(string, opers)

    else # string contains that character...

      # This is hard to deobfuscate. It substitutes subexpression with highest priority with
      # its value (e.g. chooses random value for XdY, or counts value of N+M or N*M), and
      # calls recursively evaluate with substituted string.

      evaluate(string.sub(/(\d+)?\s*(#{opers.last})\s*(\d+)/i) { a,c=0,$3.to_i; ($2 == 'd') ? ($1||1).to_i.times{a+=rand c}+a : $1.to_i.send($2,c) }, opers)

    end
  end
end
2
ответ дан 29 November 2019 в 20:09
поделиться

питон, 197 символов в скрытой версии.

Читаемая версия: 369 знаков. Нет eval, прямой синтаксический анализ.

import random
def dice(s):
    return sum(term(x) for x in s.split('+'))
def term(t):
    p = t.split('*')
    return factor(p[0]) if len(p)==1 else factor(p[0])*factor(p[1])
def factor(f):
    p = f.split('d')
    if len(p)==1:
        return int(f)
    return sum(random.randint(1, int(g[1]) if g[1] else 6) for \
               i in range(int(g[0]) if g[0] else 1))

сжатая версия: 258 символов, односимвольные имена, неправильные условные выражения, сокращение в логическом выражении:

import random
def d(s):
 return sum(t(x.split('*')) for x in s.split('+'))
def t(p):
 return f(p[0])*f(p[1]) if p[1:] else f(p[0])
def f(s):
 g = s.split('d')
 return sum(random.randint(1, int(g[1] or 6)) for i in range(int(g[0] or 1))) if g[1:] else int(s)

скрытая версия: 216 символов, использование сокращения, отображение сильно, чтобы избежать "def", " return ".

import random
def d(s):
 return sum(map(lambda t:reduce(lambda x,y:x*y,map(lambda f:reduce(lambda x,y:sum(random.randint(1,int(y or 6)) for i in range(int(x or 1))), f.split('d')+[1]),t.split('*')),1),s.split('+')))

Последняя версия: 197 символов, свернутые в комментариях @ Brain, добавлены тестовые прогоны.

import random
R=reduce;D=lambda s:sum(map(lambda t:R(int.__mul__,map(lambda f:R(lambda x,y:sum(random.randint(1,int(y or 6))for i in[0]*int(x or 1)),f.split('d')+[1]),t.split('*'))),s.split('+')))

Тесты:

>>> for dice_expr in ["3d6 + 12", "4*d12 + 3","3d+12", "43d29d16d21*9+d7d9*91+2*d24*7"]: print dice_expr, ": ", list(D(dice_expr) for i in range(10))
... 
3d6 + 12 :  [22, 21, 22, 27, 21, 22, 25, 19, 22, 25]
4*d12 + 3 :  [7, 39, 23, 35, 23, 23, 35, 27, 23, 7]
3d+12 :  [16, 25, 21, 25, 20, 18, 27, 18, 27, 25]
43d29d16d21*9+d7d9*91+2*d24*7 :  [571338, 550124, 539370, 578099, 496948, 525259, 527563, 546459, 615556, 588495]

Это решение не может обрабатывать пробелы без соседних цифр. поэтому «43d29d16d21 * 9 + d7d9 * 91 + 2 * d24 * 7» будет работать, а «43d29d16d21 * 9 + d7d9 * 91 + 2 * d24 * 7» - нет из-за второго пробела (между «+» и « d "). Это можно исправить, сначала удалив пробелы из s, но это сделает код длиннее 200 символов, поэтому я оставлю ошибку.

3
ответ дан 29 November 2019 в 20:09
поделиться

F # ( no eval и no regex)

233 символа

Это решение должно быть полностью универсальным, так как оно может обрабатывать практически любую строку, которую вы ей набросите, даже что-то безумное, например:

43d29d16d21 * 9 + d7d9 * 91 + 2 * d24 * 7

Необходимо определить это глобально:

let r = new System.Random()

Полностью запутанная версия:

let f(s:string)=let g d o i p (t:string)=t.Split([|d|])|>Array.fold(fun s x->o s (p x))i in g '+'(+)0(g '*' (*) 1 (fun s->let b=ref true in g 'd'(+)1(fun t->if !b then b:=false;(if t.Trim()=""then 1 else int t)else r.Next(int t))s))s

Читаемая версия:

let f (s:string) =
    let g d o i p (t:string) =
        t.Split([|d|]) |> Array.fold (fun s x -> o s (p x)) i
    g '+' (+) 0 (g '*' (*) 1 (fun s ->
                                        let b = ref true
                                        g 'd' (+) 1 (fun t ->
                                        if !b then b := false; (if t.Trim() = "" then 1 else int t)
                                        else r.Next(int t)) s)) s

Я призываю кого-нибудь превзойти это решение (на любом языке) без , используя eval или регулярные выражения. Я думаю, что это возможно, но мне все еще интересно увидеть подход.

4
ответ дан 29 November 2019 в 20:09
поделиться

Python 124 символа с eval, 154 без.

Чтобы показать, что python не имеет для чтения, вот решение для 124 символов с подход, основанный на eval, похожий на исходный:

import random,re
f=lambda s:eval(re.sub(r'(\d*)d(\d+)',lambda m:int(m.group(1)or 1)*('+random.randint(1,%s)'%m.group(2)),s))

[Edit] А вот 154 символа без eval:

import random,re
f=lambda s:sum(int(c or 0)+sum(random.randint(1,int(b))for i in[0]*int(a or 1))for a,b,c in re.findall(r'(\d*)d(\d+)(\s*[+-]\s*\d+)?',s))

Примечание: оба будут работать для таких входов, как «2d6 + 1d3 + 5», но не поддерживают более сложные варианты, такие как «2d3d6» или отрицательные кубики (» 1d6-4 "нормально, а" 1d6-2d4 "нет) (вместо этого вы можете убрать 2 символа, чтобы не поддерживать отрицательные числа во втором)

3
ответ дан 29 November 2019 в 20:09
поделиться

perl , без вычислений, 144 символа, работает несколько раз, поддерживает несколько бросков кубиков

sub e{($c=pop)=~y/+* /PT/d;$b='(\d+)';map{$a=0while$c=~s!$b?$_$b!$d=$1||1;$a+=1+int rand$2for 1..$d;$e=$2;/d/?$a:/P/?$d+$e:$d*$e!e}qw(d T P);$c}

Расширенная версия с комментариями

sub f {
    ($c = pop); #assign first function argument to $c
    $c =~ tr/+* /PT/d;  #replace + and * so we won't have to escape them later.
                        #also remove spaces
    #for each of 'd','T' and 'P', assign to $_ and run the following
    map {
        #repeatedly replace in $c the first instance of <number> <operator> <number> with
        #the result of the code in second part of regex, capturing both numbers and
        #setting $a to zero after every iteration
        $a=0 while $c =~ s[(\d+)?$_(\d+)][
            $d = $1 || 1;   #save first parameter (or 1 if not defined) as later regex 
                            #will overwrite it
            #roll $d dice, sum in $a
            for (1..$d)
            {
                $a += 1 + int rand $2;
            }
            $e = $2;        #save second parameter, following regexes will overwrite
            #Code blocks return the value of their last statement
            if (/d/)
            {
                $a; #calculated dice throw
            }
            elsif (/P/)
            {
                $d + $e;
            }
            else
            {
                $d * $e;
            }
        ]e;
    } qw(d T P);
    return $c;
}

РЕДАКТИРОВАТЬ очищено, обновленное объяснение к последняя версия

3
ответ дан 29 November 2019 в 20:09
поделиться

perl версия eval, 72 символа

sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=1+int rand$2-1for 0...$1-1;eval$_}

работает как

print e("4*d12+3"),"\n";

На основе решения ruby, может запускаться только один раз (вы должны undef $ a между

более короткая версия, 68 символов, напуганные (на основе 0) кости

sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=int rand$2for 0...$1-1;eval$_}

РЕДАКТИРОВАТЬ

Perl 5.8.8 не нравилась предыдущая версия, вот версия на 73 символа, которая работает

sub e{$_=pop;s/(\d+)?d(\d+)/\$a/i;$a+=1+int rand$2-1for 1...$1||1;eval$_}

Версия на 70 символов поддержка нескольких роликов

sub e{$_=pop;s/(\d*)d(\d+)/$a=$1||1;$a+=int rand$a*$2-($a-1)/ieg;eval}
4
ответ дан 29 November 2019 в 20:09
поделиться

Clojure, 854 символа как есть, 412 сжато

Просто запустите "(бросьте кости" input-string ")".

(defn roll-dice
  [string]
  (let [parts (. (. (. string replace "-" "+-") replaceAll "\\s" "") split "\\+")
        dice-func (fn [d-notation]
                    (let [bits (. d-notation split "d")]
                      (if (= 1 (count bits))
                        (Integer/parseInt (first bits))  ; Just a number, like 12
                        (if (zero? (count (first bits)))
                          (inc (rand-int (Integer/parseInt (second bits))))  ; Just d100 or some such
                          (if (. (first bits) contains "*")
                            (* (Integer/parseInt (. (first bits) replace "*" ""))
                                (inc (rand-int (Integer/parseInt (second bits)))))
                            (reduce +
                              (map #(+ 1 %)
                                    (map rand-int
                                        (repeat
                                          (Integer/parseInt (first bits))
                                          (Integer/parseInt (second bits)))))))))))]      
    (reduce + (map dice-func parts))))

Для сжатия я сделал переменные 1 буквой, переместил (первые биты) / (вторые биты) в переменные, сделал dice-func анонимной функцией, сделал оболочку для Integer .parseInt вызвал 'i' и удалил комментарии и лишние пробелы.

Это должно работать со всем действительным, с пробелами или без них. Только не спрашивайте «15dROBERT», это вызовет исключение.

Они работают по принципу разделения строки на кубики (это 3-я строка, let). Итак, «5d6 + 2 * d4-17» становится «5d6», «2 * d4», «- 17».

Каждый из них затем обрабатывается функцией dice-func, и результаты складываются (это это карта / сокращение в последней строке)

Dice-func берет маленькую цепочку игральных костей (например, "5d6") и разбивает ее на "d". Если осталась только одна часть, это было простое число (6, -17 и т. Д.).

Если первая часть содержит *, мы умножаем это число на случайное целое число, от 1 до (число после d), включительно.

Если первая часть не содержит *, мы берем первое число случайных бросков (как и в предыдущей строке) и складываем их (это карта / уменьшение посередине).

Это было весело небольшая проблема.

Итак, «5d6 + 2 * d4-17» становится «5d6», «2 * d4», «- 17».

Каждый из них затем обрабатывается функцией dice-func, и результаты складываются (это это карта / сокращение в последней строке)

Dice-func берет маленькую цепочку игральных костей (например, "5d6") и разбивает ее на "d". Если осталась только одна часть, это было простое число (6, -17 и т. Д.).

Если первая часть содержит *, мы умножаем это число на случайное целое число, от 1 до (число после d), включительно.

Если первая часть не содержит *, мы берем первое число случайных бросков (как и в предыдущей строке) и складываем их (это карта / уменьшение посередине).

Это было весело небольшая проблема.

Итак, «5d6 + 2 * d4-17» становится «5d6», «2 * d4», «- 17».

Каждый из них затем обрабатывается функцией dice-func, и результаты складываются (это это карта / сокращение в последней строке)

Dice-func берет маленькую цепочку игральных костей (например, "5d6") и разбивает ее на "d". Если осталась только одна часть, это было простое число (6, -17 и т. Д.).

Если первая часть содержит *, мы умножаем это число на случайное целое число, от 1 до (число после d), включительно.

Если первая часть не содержит *, мы берем первое число случайных бросков (как и в предыдущей строке) и складываем их (это карта / уменьшение посередине).

Это было весело небольшая проблема.

Каждый из них затем обрабатывается функцией dice-func, и результаты складываются (это карта / уменьшение в последней строке).

Dice-func берет небольшую строку игральных костей (например, "5d6 ") и разбивает его на" d ". Если осталась только одна часть, это было простое число (6, -17 и т. Д.).

Если первая часть содержит *, мы умножаем это число на случайное целое число, от 1 до (число после d), включительно.

Если первая часть не содержит *, мы берем первое число случайных бросков (как и в предыдущей строке) и складываем их (это карта / уменьшение посередине).

Это было весело небольшая проблема.

Каждый из них затем обрабатывается функцией dice-func, и результаты складываются (это карта / уменьшение в последней строке).

Dice-func берет небольшую строку игральных костей (например, "5d6 ") и разбивает его на" d ". Если осталась только одна часть, это было простое число (6, -17 и т. Д.).

Если первая часть содержит *, мы умножаем это число на случайное целое число, от 1 до (число после d), включительно.

Если первая часть не содержит *, мы берем первое число случайных бросков (как и в предыдущей строке) и складываем их (это карта / уменьшение посередине).

Это было весело небольшая проблема.

4
ответ дан 29 November 2019 в 20:09
поделиться

J

С помощью cobbal сжать все до 93 символов.

$ jconsole
   e=:".@([`('%'"_)@.(=&'/')"0@,)@:(3 :'":(1".r{.y)([:+/>:@?@$) ::(y&[)0".}.y}.~r=.y i.''d'''@>)@;:

   e '3d6 + 12'
20
   e 10$,:'3d6 + 12'
19 23 20 26 24 20 20 20 24 27
   e 10$,:'4*d12 + 3'
28 52 56 16 52 52 52 36 44 56
   e 10$,:'d100'
51 51 79 58 22 47 95 6 5 64
5
ответ дан 29 November 2019 в 20:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: