算法用于石头,剪刀,布游戏

huangapple go评论65阅读模式
英文:

Algorithm for rock, paper, scissors game

问题

这是一个略有不同的古老的Java石头,剪刀,布示例。在这种情况下,用户输入输入(我假设是有效的,即只使用R、P和S的组合,并且括号匹配,没有空格),例如,(R&S) 的输出是 R,因为石头打败剪刀,或者 ((R&S)&(P&R)) 的输出是 P

现在到目前为止,我有一段代码(如下)可以分割字符串,迭代并将使用的字母放入列表中,因为我的想法是从左到右读取,评估直到达到末尾,但在这一点上,我陷入了困境,因为如何有效地跟踪所有的“先前”结果呢?我需要另一个空列表吗?而且使用情况似乎不可行,因为输入可能很长,而且完全是随机的R、P和S的组合。任何建议都将不胜感激!

import java.util.ArrayList;
import java.util.Scanner;

public class RPS {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        str = str.replaceAll("&\\(", "").replaceAll("&\\)","");
        String inputs[] = str.split("&");
        ArrayList<Object> list = new ArrayList<>();

        for (int i = 0; i < inputs.length; i++){
            if (inputs[i].substring(0, 1).contains("R")) {
                list.add(inputs[i]);
            } else if (inputs[i].substring(0, 1).contains("S")) {
                list.add(inputs[i]);
            } else if (inputs[i].substring(0, 1).contains("P")) {
                list.add(inputs[i]);
            }
        }
        for (int i = 0; i < list.size(); i++){
            if (list.contains("R") && list.contains("S")){ //例如,如果输入是“(R&amp;S)”
                System.out.println("R");
                break;
            }
        }
    }
}
英文:

So this is a slightly different take on the age old rock, paper, scissors java example. In this situation, the user enters the input (that I'm assuming is valid, i.e. uses only combinations of R,P, & S, and has matching parenthesis, also no spaces) like for example, (R&amp;S) the output is R because Rock beats Scissors, or ((R&amp;S)&amp;(P&amp;R)) outputs P.

Now so far I have code (below) that can split the strings, iterate through and get the letters used into a list, because my idea was just to read from left to right, evaluating until I get to the end but at this point I'm stumped because what would be a good way to keep track of all the "previous" results. Would I need another empty list? Also using cases doesn't seem viable since the input can be long and also completely random combination of R,P, and S. Any advice is appreciated!

import java.util.ArrayList;
import java.util.Scanner;

public class RPS {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        str = str.replaceAll(&quot;\\(&quot;, &quot;&quot;).replaceAll(&quot;\\)&quot;,&quot;&quot;);
        String inputs[] = str.split(&quot;&amp;&quot;);
        ArrayList&lt;Object&gt; list = new ArrayList&lt;&gt;();

        for (int i = 0; i &lt; inputs.length; i++){
            if (inputs[i].substring(0, 1).contains(&quot;R&quot;)) {
                list.add(inputs[i]);
            } else if (inputs[i].substring(0, 1).contains(&quot;S&quot;)) {
                list.add(inputs[i]);
            } else if (inputs[i].substring(0, 1).contains(&quot;P&quot;)) {
                list.add(inputs[i]);
            }
        }
        for (int i = 0; i &lt; list.size(); i++){
            if (list.contains(&quot;R&quot;) &amp;&amp; list.contains(&quot;S&quot;)){ //ex. if the input was &quot;(R&amp;S)&quot;
                System.out.println(&quot;R&quot;);
                break;
            }
        }

    }

}

答案1

得分: 1

如果您处理输入并将其转换为逆波兰表示法,您可以使用一个“栈”来保存值和运算符。

这是我的意思。以您的简单输入为例。

(R&S)

在“栈”上,它会是这样的:

R
S
&

栈始终应该以两个值和一个运算符开始。

让我们来看看您更复杂的示例。

((R&S)&(P&R))

在“栈”上,它会是这样的:

 R
 S
 &
 P
 R
 &
 &

您会用结果替换“栈”上的RS&。然后您会用结果替换“栈”上的PR&。最终的结果将使用最后的&运算符处理。

英文:

If you process your input and convert it to reverse polish notation, you can use a Stack to hold the values and the operators.

Here's what I mean. Take your simple input.

(R&amp;S)

On a Stack, it would look like:

R
S
&amp;

The stack should always start with two values and one operator.

Let's take your more complicated example.

((R&amp;S)&amp;(P&amp;R))

On a Stack, it would look like:

 R
 S
 &amp;
 P
 R
 &amp;
 &amp;

You'd replace the RS&amp; on the Stack with the result. Then you'd replace the PR&amp; on the Stack with the result. The final result would be processed with the last &amp; operator.

答案2

得分: 1

使用递归编写一个evaluate函数是解决这个问题的一种方法。它会接受一个字符串作为输入,基本情况是单个字符RPS。否则,它会在顶层的与号上分割字符串,并递归地评估与号左侧和右侧的字符串,并使用返回的字符来确定结果。顶层的与号可以在不在括号集合内(如果存在外层冗余括号,则不计算在内)的情况下找到。

例如,以下是在Java中的实现。

import java.util.Stack;

public class RPS {
    // 去除冗余的包围括号,使字符串规范化。
    private static String normalize(String s) {
        // 首先,计算前导开括号的数量。
        int leading = 0;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) != '(')
                break;
            ++leading;
        }
        if (leading > 0) {
            // 对于每个闭括号,计算匹配开括号的位置。与前导开括号成对出现的尾部闭括号是多余的。
            Stack<Integer> stack = new Stack<Integer>();
            for (int i = 0; i < s.length(); ++i) {
                char c = s.charAt(i);
                if (c == '(') {
                    stack.push(i);
                } else if (c == ')') {
                    int j = stack.pop();
                    if (j < leading && j + i + 1 == s.length())
                        return s.substring(j + 1, s.length() - j - 1);
                }
            }   
        }
        return s;
    }
    
    private static char evaluate(String s) {
        s = normalize(s);
        // 单个字符评估为其自身
        if (s.length() == 1)
            return s.charAt(0);
        // 找到顶层的与号位置,即出现在匹配的括号对之外的与号。
        int depth = 0;
        int position = -1;
        for (int i = 0; i < s.length(); ++i) {
            char c = s.charAt(i);
            if (c == '(')
                depth += 1;
            else if (c == ')')
                depth -= 1;
            else if (depth == 0 && c == '&') {
                position = i;
                break;
            }
        }
        // 否则,在顶层与号上分割并评估左侧和右侧。
        char left = evaluate(s.substring(0, position));
        char right = evaluate(s.substring(position + 1));
        // 返回获胜者
        if (left == right)
            return left;
        switch (left) {
            case 'R':
                return right == 'P' ? 'P' : 'R';
            case 'P':
                return right == 'S' ? 'S' : 'P';
            case 'S':
                return right == 'R' ? 'R' : 'S';
            default:
                throw new RuntimeException();    
        }
    }
    
    public static void main(String[] args) {
        System.out.println(evaluate("((R&S)&(P&R))"));
        System.out.println(evaluate("(R&S)&(P&R)"));
        System.out.println(evaluate("(R)"));
        System.out.println(evaluate("((((R&P))&((S))))"));
        System.out.println(evaluate("((R&S)&R)"));
        System.out.println(evaluate("S"));
        System.out.println(evaluate("(((R&P)&(S&P))&(P&R))"));
    }
}

输出:

P
P
R
S
R
S
S
英文:

One way to solve this would be to write a recursive evaluate function. It would take a string as input, with the base case being a single character R, P, or S. Otherwise, it would split the string on the top-level ampersand, and recursively evaluate the string to the left and right of the ampersand, and use the returned characters to determine the result. The top-level ampersand could be found as the ampersand occurring not within a set of parentheses (not counting any outermost redundant parentheses if they exist).

For example, here's an implementation in Java.

import java.util.Stack;

public class RPS {
    // Normalize string by removing surrounding parentheses that are redundant.
    private static String normalize(String s) {
        // First, count the number of leading open parentheses.
        int leading = 0;
        for (int i = 0; i &lt; s.length(); ++i) {
            if (s.charAt(i) != &#39;(&#39;)
                break;
            ++leading;
        }
        if (leading &gt; 0) {
            // For each closing parenthesis, compute the position of the
            // matching opening parenthesis. The set of trailing parentheses
            // paired with leading parentheses are redundant.
            Stack&lt;Integer&gt; stack = new Stack&lt;Integer&gt;();
            for (int i = 0; i &lt; s.length(); ++i) {
                char c = s.charAt(i);
                if (c == &#39;(&#39;) {
                    stack.push(i);
                } else if (c == &#39;)&#39;) {
                    int j = stack.pop();
                    if (j &lt; leading &amp;&amp; j + i + 1 == s.length())
                        return s.substring(j + 1, s.length() - j - 1);
                }
            }   
        }
        return s;
    }
    
    private static char evaluate(String s) {
        s = normalize(s);
        // A single character evaluates to itself
        if (s.length() == 1)
            return s.charAt(0);
        // Find the position of the top-level ampersand, which is the ampersand
        // occurring outside matched pairs of parentheses.
        int depth = 0;
        int position = -1;
        for (int i = 0; i &lt; s.length(); ++i) {
            char c = s.charAt(i);
            if (c == &#39;(&#39;)
                depth += 1;
            else if (c == &#39;)&#39;)
                depth -= 1;
            else if (depth == 0 &amp;&amp; c == &#39;&amp;&#39;) {
                position = i;
                break;
            }
        }
        // Otherwise, split on the top-level ampersand and evaluate the left
        // and right sides.
        char left = evaluate(s.substring(0, position));
        char right = evaluate(s.substring(position + 1));
        // Return the winner
        if (left == right)
            return left;
        switch (left) {
            case &#39;R&#39;:
                return right == &#39;P&#39; ? &#39;P&#39; : &#39;R&#39;;
            case &#39;P&#39;:
                return right == &#39;S&#39; ? &#39;S&#39; : &#39;P&#39;;
            case &#39;S&#39;:
                return right == &#39;R&#39; ? &#39;R&#39; : &#39;S&#39;;
            default:
                throw new RuntimeException();    
        }
    }
    
    public static void main(String[] args) {
        System.out.println(evaluate(&quot;((R&amp;S)&amp;(P&amp;R))&quot;));
        System.out.println(evaluate(&quot;(R&amp;S)&amp;(P&amp;R)&quot;));
        System.out.println(evaluate(&quot;(R)&quot;));
        System.out.println(evaluate(&quot;((((R&amp;P))&amp;((S))))&quot;));
        System.out.println(evaluate(&quot;((R&amp;S)&amp;R)&quot;));
        System.out.println(evaluate(&quot;S&quot;));
        System.out.println(evaluate(&quot;(((R&amp;P)&amp;(S&amp;P))&amp;(P&amp;R))&quot;));
    }
}

Output:

P
P
R
S
R
S
S

答案3

得分: 1

以下是翻译好的内容:

Java

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public class RPS {
    private static class Node {
        Character data = null;
        List<Node> children = null;
    }
    
    private static Node parse(Queue<Character> tokens) {
        // 警告:会破坏输入内容
        char token = tokens.remove();
        Node node = new Node();
        if (token == '(') {
            node.children = new ArrayList<Node>();
            while (tokens.peek() != ')') {
                node.children.add(parse(tokens));
            }
            char c = tokens.remove();
            if (c != ')')
                throw new RuntimeException();
        } else if (token == ')') {
            throw new RuntimeException();
        } else {
            node.data = token;
        }
        return node;
    }
    
    private static char _evaluate(Node tree) {
        if (tree.data != null) {
            return tree.data;
        } else if (tree.children.size() == 1) {
            return _evaluate(tree.children.get(0));
        } else {
            char left = _evaluate(tree.children.get(0));
            if (!tree.children.get(1).data.equals('&'))
                throw new RuntimeException();
            char right = _evaluate(tree.children.get(2));
            // 返回获胜者
            if (left == right)
                return left;
            switch (left) {
                case 'R':
                    return right == 'P' ? 'P' : 'R';
                case 'P':
                    return right == 'S' ? 'S' : 'P';
                case 'S':
                    return right == 'R' ? 'R' : 'S';
                default:
                    throw new RuntimeException();    
            }
        }
    }
    
    private static Set<Character> VALID_CHARS =
            new HashSet<Character>() {{
                add('(');
                add(')');
                add('&');
                add('R');
                add('P');
                add('S');
            }};
    
    public static char evaluate(String s) {
        Queue<Character> tokens = new LinkedList<Character>();
        tokens.add('(');
        for (int i = 0; i < s.length(); ++i) {
            char c = Character.toUpperCase(s.charAt(i));
            if (Character.isWhitespace(c))
                continue;
            if (!VALID_CHARS.contains(c))
                throw new RuntimeException();
            tokens.add(c);
        }
        tokens.add(')');
        Node tree = parse(tokens);
        char c = _evaluate(tree);
        return c;
    }
    
    public static void main(String[] args) {
        System.out.println(evaluate("((R&S)&(P&R))"));          // P
        System.out.println(evaluate("(R&S)&(P&R)"));            // P
        System.out.println(evaluate("( R )"));                  // R
        System.out.println(evaluate("((((R&P))&((S))))"));      // S
        System.out.println(evaluate("((R&S)&R)"));              // R
        System.out.println(evaluate("S"));                      // S
        System.out.println(evaluate("(((R&P)&(S&P))&(P&R))"));  // S
    }
}

Python

from collections import deque
from typing import Union

def parse(tokens: deque):
    # 警告:会破坏输入内容
    token = tokens.popleft()
    if token == '(':
        result = []
        while tokens[0] != ')':
            result.append(parse(tokens))
        tokens.popleft()  # closing ')'
        return result
    else:
        return token

def _evaluate(tree: Union[list, str]):
    if type(tree) != list:
        return tree
    elif len(tree) == 1:
        return _evaluate(tree[0])
    else:
        left = _evaluate(tree[0])
        right = _evaluate(tree[2])
        pair = left + right
        lookup = {
            'RP': 'P', 'PR': 'P', 'PP': 'P',
            'RS': 'R', 'SR': 'R', 'RR': 'R',
            'PS': 'S', 'SP': 'S', 'SS': 'S',
        }
        return lookup[pair]

def evaluate(s: str):
    tokens = deque(f'({s})')
    tree = parse(tokens)
    return _evaluate(tree)

# 示例用法
print(evaluate('((R&S)&(P&R))'))          # P
print(evaluate('(R&S)&(P&R)'))            # P
print(evaluate('(R)'))                    # R
print(evaluate('((((R&P))&((S))))'))      # S
print(evaluate('((R&S)&R)'))              # R
print(evaluate('S'))                      # S
print(evaluate('(((R&P)&(S&P))&(P&R))'))  # S
英文:

One way to solve this is to first parse the string into a tree where nodes are either 1) a character or 2) a group of children nodes representing items in parentheses. Then call a recursive evaluation function on the tree.

For example, here's an implementation in Java that has error checking and support for white spaces (which are ignored), followed by my initial prototype in Python, which is shorter, but does not include error checking nor support for white spaces.

Java

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public class RPS {
    private static class Node {
        Character data = null;
        List&lt;Node&gt; children = null;
    }
    
    private static Node parse(Queue&lt;Character&gt; tokens) {
        // WARN: Destructively modifies input
        char token = tokens.remove();
        Node node = new Node();
        if (token == &#39;(&#39;) {
            node.children = new ArrayList&lt;Node&gt;();
            while (tokens.peek() != &#39;)&#39;) {
                node.children.add(parse(tokens));
            }
            char c = tokens.remove();
            if (c != &#39;)&#39;)
                throw new RuntimeException();
        } else if (token == &#39;)&#39;) {
            throw new RuntimeException();
        } else {
            node.data = token;
        }
        return node;
    }
    
    private static char _evaluate(Node tree) {
        if (tree.data != null) {
            return tree.data;
        } else if (tree.children.size() == 1) {
            return _evaluate(tree.children.get(0));
        } else {
            char left = _evaluate(tree.children.get(0));
            if (!tree.children.get(1).data.equals(&#39;&amp;&#39;))
                throw new RuntimeException();
            char right = _evaluate(tree.children.get(2));
            // Return the winner
            if (left == right)
                return left;
            switch (left) {
                case &#39;R&#39;:
                    return right == &#39;P&#39; ? &#39;P&#39; : &#39;R&#39;;
                case &#39;P&#39;:
                    return right == &#39;S&#39; ? &#39;S&#39; : &#39;P&#39;;
                case &#39;S&#39;:
                    return right == &#39;R&#39; ? &#39;R&#39; : &#39;S&#39;;
                default:
                    throw new RuntimeException();    
            }
        }
    }
    
    private static Set&lt;Character&gt; VALID_CHARS =
            new HashSet&lt;Character&gt;() {{
                add(&#39;(&#39;);
                add(&#39;)&#39;);
                add(&#39;&amp;&#39;);
                add(&#39;R&#39;);
                add(&#39;P&#39;);
                add(&#39;S&#39;);
            }};
    
    public static char evaluate(String s) {
        Queue&lt;Character&gt; tokens = new LinkedList&lt;Character&gt;();
        tokens.add(&#39;(&#39;);
        for (int i = 0; i &lt; s.length(); ++i) {
            char c = Character.toUpperCase(s.charAt(i));
            if (Character.isWhitespace(c))
                continue;
            if (!VALID_CHARS.contains(c))
                throw new RuntimeException();
            tokens.add(c);
        }
        tokens.add(&#39;)&#39;);
        Node tree = parse(tokens);
        char c = _evaluate(tree);
        return c;
    }
    
    public static void main(String[] args) {
        System.out.println(evaluate(&quot;((R&amp;S)&amp;(P&amp;R))&quot;));          // P
        System.out.println(evaluate(&quot;(R&amp;S)&amp;(P&amp;R)&quot;));            // P
        System.out.println(evaluate(&quot;( R )&quot;));                  // R
        System.out.println(evaluate(&quot;((((R&amp;P))&amp;((S))))&quot;));      // S
        System.out.println(evaluate(&quot;((R&amp;S)&amp;R)&quot;));              // R
        System.out.println(evaluate(&quot;S&quot;));                      // S
        System.out.println(evaluate(&quot;(((R&amp;P)&amp;(S&amp;P))&amp;(P&amp;R))&quot;));  // S
    }
}

Python

from collections import deque
from typing import Union

def parse(tokens: deque):
    # WARN: Destructively modifies input
    token = tokens.popleft()
    if token == &#39;(&#39;:
        result = []
        while tokens[0] != &#39;)&#39;:
            result.append(parse(tokens))
        tokens.popleft()  # closing &#39;)&#39;
        return result
    else:
        return token

def _evaluate(tree: Union[list, str]):
    if type(tree) != list:
        return tree
    elif len(tree) == 1:
        return _evaluate(tree[0])
    else:
        left = _evaluate(tree[0])
        right = _evaluate(tree[2])
        pair = left + right
        lookup = {
            &#39;RP&#39;: &#39;P&#39;, &#39;PR&#39;: &#39;P&#39;, &#39;PP&#39;: &#39;P&#39;,
            &#39;RS&#39;: &#39;R&#39;, &#39;SR&#39;: &#39;R&#39;, &#39;RR&#39;: &#39;R&#39;,
            &#39;PS&#39;: &#39;S&#39;, &#39;SP&#39;: &#39;S&#39;, &#39;SS&#39;: &#39;S&#39;,
        }
        return lookup[pair]

def evaluate(s: str):
    tokens = deque(f&#39;({s})&#39;)
    tree = parse(tokens)
    return _evaluate(tree)

# Example usage
print(evaluate(&#39;((R&amp;S)&amp;(P&amp;R))&#39;))          # P
print(evaluate(&#39;(R&amp;S)&amp;(P&amp;R)&#39;))            # P
print(evaluate(&#39;(R)&#39;))                    # R
print(evaluate(&#39;((((R&amp;P))&amp;((S))))&#39;))      # S
print(evaluate(&#39;((R&amp;S)&amp;R)&#39;))              # R
print(evaluate(&#39;S&#39;))                      # S
print(evaluate(&#39;(((R&amp;P)&amp;(S&amp;P))&amp;(P&amp;R))&#39;))  # S

huangapple
  • 本文由 发表于 2020年10月27日 05:32:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/64545274.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定