英文:
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&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&S)
the output is R
because Rock beats Scissors, or ((R&S)&(P&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("\\(", "").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")){ //ex. if the input was "(R&S)"
System.out.println("R");
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&S)
On a Stack
, it would look like:
R
S
&
The stack should always start with two values and one operator.
Let's take your more complicated example.
((R&S)&(P&R))
On a Stack
, it would look like:
R
S
&
P
R
&
&
You'd replace the RS&
on the Stack
with the result. Then you'd replace the PR&
on the Stack
with the result. The final result would be processed with the last &
operator.
答案2
得分: 1
使用递归编写一个evaluate
函数是解决这个问题的一种方法。它会接受一个字符串作为输入,基本情况是单个字符R
、P
或S
。否则,它会在顶层的与号上分割字符串,并递归地评估与号左侧和右侧的字符串,并使用返回的字符来确定结果。顶层的与号可以在不在括号集合内(如果存在外层冗余括号,则不计算在内)的情况下找到。
例如,以下是在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 < s.length(); ++i) {
if (s.charAt(i) != '(')
break;
++leading;
}
if (leading > 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<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);
// 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 < 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;
}
}
// 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 '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))"));
}
}
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<Node> children = null;
}
private static Node parse(Queue<Character> tokens) {
// WARN: Destructively modifies input
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));
// Return the winner
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):
# WARN: Destructively modifies input
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)
# Example usage
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论