2016-12-30 8 views
1

Итак, я пишу основную игру MasterMind, которая ... в основном функциональна. Тем не менее, его проявление странного поведения, и я не уверен, почему.Почему моя переменная класса переписывает себя после запуска несвязанного метода?

Идея состоит в том, что то, что определяет код, и его поведение - это один файл, игровой процесс - другой, а Main просто создает новую игру и начинает играть. Когда я инициализирую игру, компьютер создает новую случайную строку из 4 («секретный код»), как и ожидалось; но затем, как только я получу ввод для пользователя, угадай, похоже, он переписывает секретный код во все, что я ввел. Кроме того, мои методы оценки совпадений не работают вообще, но, учитывая, что секретный код продолжает меняться, означает, что он не начинается, и я не уверен, почему.

Все три класса ниже. Почему моя переменная класса в игре неправильно настроена и доступна другим методам?

Main.java

class Main { 
    public static void main(String[] args) { 
    Game newGame = new Game(); 
    newGame.play(); 
    } 
} 

Code.java

import java.util.Random; 
import java.util.HashMap; 
import java.util.Collection; 
import java.util.ArrayList; 
import java.util.Set; 

import java.lang.Math; 
import java.lang.StringBuilder; 

class Code { 
    private static HashMap<String,String> PEGS; 
    private static ArrayList<String> pegStrings; 
    protected static String secretCodeString; 


    public static void main(String[] args) { 

    } 

    public Code(String input){ 
    this.secretCodeString = input; 
    } 

    public Code(){ 
    randomize(); 
    } 


    //literally just creates the peghash 
    public static void setPegs(){ 
    PEGS = new HashMap<String,String>(); 

    PEGS.put("C","c"); 
    PEGS.put("Y","y"); 
    PEGS.put("R","r"); 
    PEGS.put("P","p"); 
    PEGS.put("O","o"); 
    PEGS.put("G","g"); 
    } 

    //turns the pegs ito something randomize can use 
public static ArrayList<String> makePegArray(){ 
    setPegs(); 

    pegStrings = new ArrayList<String>(); 

    Collection<String> pegValues = PEGS.values(); 
    Object[] pegObjects = pegValues.toArray(); 

     for (int i = 0; i < pegObjects.length; i++){ 
     pegStrings.add(pegObjects[i].toString()); 
     } 

    return pegStrings; 
    } 

    // sets Class Variable secretCode to a four letter combination 
    public static Code randomize(){ 
    secretCodeString = new String(); 

    Random rand = new Random(); 
    int randIndex = rand.nextInt(makePegArray().size()); 

    for (int i = 0; i < 4; i++){ 
     randIndex = rand.nextInt(makePegArray().size()); 
     secretCodeString = secretCodeString.concat(makePegArray().get(randIndex)); 
    } 

     Code secretCode = parse(secretCodeString); 
     return secretCode; 
    } 

    public static Code parse(String input) { 
    setPegs(); 
    makePegArray(); 

    String[] letters = input.split(""); 
    StringBuilder sb = new StringBuilder(); 

    for (String letter : letters) { 
     if (pegStrings.contains(letter)) { 
     sb.append(letter); 
     } else { 
     System.out.println(letter); 
     throw new RuntimeException(); 

     } 
    } 

    String pegListString = sb.toString(); 
    Code parsedCode = new Code(pegListString); 
    //System.out.println(parsedCode); 
    return parsedCode; 

    } 

    public int countExactMatches(Code guess){ 
    String guessString = guess.secretCodeString; 

    int exactMatches = 0; 

    String[] guessArray = guessString.split(""); 

    String[] winningCodeArray = (this.secretCodeString).split(""); 

    for(int i = 0; i < 4; i++){ 

     if(guessArray[i] == winningCodeArray[i]){ 
     exactMatches++; 
     } 
    } 
    return exactMatches; 
    } 

    public int countNearMatches(Code guess) { 

    String guessString= guess.secretCodeString; 

    HashMap<String,Integer> guessCount = new HashMap<String,Integer>(); 
    HashMap<String,Integer> secretCodeCount = new HashMap<String,Integer>(); 

    Set<String> codeKeys = guessCount.keySet(); 

    int matches = 0; 
    int keys = guessCount.keySet().size(); 


    String[] keyArray = new String[keys]; 



    for(int i = 0; i < guessString.length(); i++) { 
     //removes character from string 
     String codeCharacter = String.valueOf(guessString.charAt(i)); 
     String guessShort = guessString.replace(codeCharacter,""); 

     //counts instances of said character 
     int count = guessString.length() - guessShort.length(); 

     guessCount.put(codeCharacter, count); 
    } 

    for(int i = 0; i < secretCodeString.length(); i++) { 
     //removes character from string 
     String winningString = this.secretCodeString; 

     String winningCodeCharacter = String.valueOf(winningString.charAt(i)); 
     String winningCodeShort = guessString.replace(winningCodeCharacter,""); 

     //counts instances of said character 
     int count = winningString.length() - winningCodeShort.length(); 

     secretCodeCount.put(winningCodeCharacter, count); 
    } 

    for (int i = 0; i < keys; i++) { 
     codeKeys.toArray(keyArray); 
     String keyString = keyArray[i]; 

     if (secretCodeCount.containsKey(keyString)) { 
     matches += Math.min(secretCodeCount.get(keyString), guessCount.get(keyString)); 
     } 
    } 

    int nearMatches = matches - countExactMatches(guess); 

    return nearMatches; 
    } 
} 

Game.java

import java.util.Scanner; 

class Game { 

    protected static Code winningCode; 

    public static void main(String[] args){ 

    } 

    public Game(){ 
    winningCode = new Code(); 
    } 

    protected static Code getGuess() { 

    Scanner userInput = new Scanner(System.in); 

    int count = 0; 
    int maxTries = 5; 
    while(true){ 
     try { 
     String codeToParse = userInput.next(); 
     Code guess = Code.parse(codeToParse); 
     return guess; 

     } catch(RuntimeException notACode) { 
     System.out.println("That's not a valid peg. You have " + (maxTries - count) + " tries left."); 
     if (++count == maxTries) throw notACode; 
     } 
    } 


    } 

    protected static void displayMatches(Code guess){ 

    int nearMatches = winningCode.countNearMatches(guess); 
    int exactMatches = winningCode.countExactMatches(guess); 

    System.out.println("You have " + exactMatches + " exact matches and " + nearMatches + " near matches."); 
    } 

    protected static void play(){ 
    int turnCount = 0; 
    int maxTurns = 10; 

    System.out.println("Greetings. Pick your code of four from Y,O,G,P,C,R."); 

    while(true){ 
     Code guess = getGuess(); 
     displayMatches(guess); 

     if (guess == winningCode) { 
     System.out.print("You win!!"); 
     break; 
     } else if (++turnCount == maxTurns) { 
     System.out.print("You lose!!"); 
     break; 
     } 
    } 
    } 
} 
+4

Почему вы объявляете все как статическое? Плохо. http://stackoverflow.com/questions/2671496/java-when-to-use-static-methods – OldProgrammer

+0

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

+2

Нет, нет, нет. Вы делаете это, потому что Main() объявлен статическим. Вам нужно создать экземпляр класса (объекта) в Main(), а затем ссылаться на этот объект через объект. Прочтите ссылку в комментарии. – OldProgrammer

ответ

3

На каждом догадка, вы называете Code.parse, Code.parse создает новый Code (new Code(pegListString);) и этот конструктор устанавливает secretCodeString и потому что это статично, все экземпляры Code используют одну и ту же переменную. Вам нужно избегать изменчивых static пользователей.

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

+0

Я понимаю, что вы имеете в виду, но у меня есть второй конструктор, который принимает входные данные и должен установить значение String кода в аргумент, предоставленный 'this.secretCodeString = input'. Это недействительно теперь, когда есть конструктор randomize/no params? –

+0

Понятно, что я пропустил это, ну это все равно похоже на то, о чем я думал, поскольку оба конструктора изменяют общее статическое поле 'secretCodeString'. – weston

1

«Почему моя переменная класса переписывается после того, как выполняется несвязанный метод?»

Потому что, на самом деле, это не связано. «Беспорядок», который вы создали путем объявления переменных и методов как static, привел к нежелательной связи между различными частями вашего кода.

Трудно сказать, какое правильное решение здесь, потому что ваш код настолько смущен переписываниями, что трудно отличить оригинальное «намерение проекта».

Моим советом было бы начать снова. Теперь у вас должно быть более четкое представление о том, какая функциональность требуется. Что вам нужно сделать, так это повторить дизайн объекта, чтобы каждый класс имел четкую цель. (Классы Main и Game имеют смысл, но Code, похоже, представляет собой mashup функциональности и состояния, которое не имеет согласованной цели.)