Проблемы с условиями победы TicTacToe

Новый программист здесь, пишет игру Tictactoe, используя Java для Eclipse.

Думаю, у меня проблемы с условиями победы. Возникает ошибка: Исключение в потоке "main" java.lang.NullPointerException в Game.NoughtsCrosses.(NoughtsCrosses.java:106) в Game.Main.main(Main.java:5)

Вот мои условия победы. Это не очень хорошо сделано, но у меня проблемы при компиляции. Кто-нибудь может определить, почему? Тай!!

У меня есть квадраты, расположенные в сетке 3x3, 0 -> 8. Каждая кнопка имеет свой собственный текст, который устанавливается на X или O при нажатии каждым игроком.

код винкондишнса:

if (square[0].getText().equals(square[1].getText()) && square[1].getText().equals(square[2].getText()) != square[0].getText().isEmpty()) {
    win = true;
}

Полная вставка кода

Еще раз спасибо :) Любые вопросы, я могу уточнить: D


person Sphyxx    schedule 11.07.2013    source источник
comment
1) Нет необходимости добавлять основной тег в заголовок. 2) Чтобы быстрее получить помощь, опубликуйте SSCCE.   -  person Andrew Thompson    schedule 12.07.2013
comment
К вашему сведению, на самом деле это ошибка времени выполнения, а не ошибка времени компиляции.   -  person DaoWen    schedule 12.07.2013
comment
просто хотел сообщить вам, что я обновил свой ответ ниже.   -  person Legion    schedule 12.07.2013


Ответы (6)


Что ж, я взял код, который вы предоставили, и после значительных усилий смог создать полностью функционирующую игру «Крестики-нолики». Вы были в основном на правильном пути в том, что вы делали, вам просто нужно было сначала начать с дизайна.

В моем классе NoughtsCrosses у меня есть следующее:

  • class Action implements ActionListener
    • This has a JButton attribute that I pass in through a constructor
    • In the actionPerformed
      • set the text
      • отключить кнопку
      • увеличить счетчик
      • check if someone wins
        • If there is a winner or draw game ends set the "Play again?" text
        • иначе вызовите функцию changeTurn
  • class Reset implements ActionListenter
    • This has a JButton attribute that I pass in through a constructor
    • In the actionPerformed
      • I call the resetGame function
  • функция changeTurn
  • функция сброса игры
  • функция проверкиForWinners

как подсказка, это моя реализация класса Action и пример конструктора, о котором я упоминал

class Action implements ActionListener{ 
 private JButton button;
 public Action(JButton button){ 
  this.button = button; 
 } 
 public void actionPerformed(ActionEvent e) { 
   button.setText(letter); 
   button.setEnabled(false); 
   counter++; 
   boolean gameOver = checkForWinners(); 
   if(!gameOver) 
    changeTurn(); 
   else{ 
    newgame.setText("Play again?"); 
    newgame.addActionListener(resetButton); 
   } 
 } 
}

такой вызов, как new Action(square[i]), - это то, что вам нужно, чтобы это работало. Примечание: resetButton относится к классу Reset, о котором я упоминал выше, так же, как и класс Action, он имеет ту же конструкцию, в которую я передал newgame.

person Legion    schedule 11.07.2013
comment
вот базовый дизайн для программы, которую вы хотите. Как я уже сказал, у меня есть полностью рабочая версия, поэтому спрашивайте меня, если у вас есть вопросы по ее реализации. - person Legion; 12.07.2013
comment
Большое спасибо, вы спасаете жизнь :D Вы сильно изменили графический интерфейс или все выглядит нормально? Вы сохранили кнопки в одномерном массиве или изменили их на два многомерных массива? - person Sphyxx; 12.07.2013
comment
Я хранил их в одномерном массиве. Единственное, что я изменил в графическом интерфейсе, это добавил отсутствующий ActionListener для сброса игры, в остальном все было в порядке! - person Legion; 12.07.2013
comment
Ах хорошо. По крайней мере, я в порядке со Swing: P Хорошо, я бездельничал, кажется, теперь работает. Извините за нубский вопрос, но я могу заставить игру ввести один квадрат, изменив его на X, но тогда он не работает ++ (я думаю, что игрок не меняется) и не могу выбрать другую кнопку. Могу ли я спросить, как вы использовали функцию changeTurn? Извините, я новичок в этом :D - person Sphyxx; 12.07.2013
comment
Без проблем. В моей реализации я увеличил счетчик в классе Action, затем проверил победителей или ничью, а затем вызвал changeTurn, который имеет этот код из того, что вы написали: if (counter % 2 == 0){ player = 1; letter = "X"; } else{ player = 2; letter = "O"; } playergo.setText("It is Player " + player + "'s Turn"); - person Legion; 12.07.2013
comment
Хорошо сделал еще немного редактирования. Помимо многих синтаксических ошибок: введите }, чтобы закончить тело класса (которых у меня, кажется, много: P), я обновил свой pastebin своим прогрессом, у меня, похоже, возникли проблемы с вызовом функций при проверке выигрышных комбинаций и проверке resetTurn или что-то. Большое спасибо за всю вашу помощь, как я могу отплатить вам :D - person Sphyxx; 12.07.2013
comment
Становится неплохо. Вам все еще нужно передать кнопку в ваши экземпляры Action, например square[i].addActionListener(new Action(square[i]));, также с тем, как вы ее настроили, вам нужны переменные player и counter в качестве глобальных переменных (там же, где у вас есть объекты качания). Некоторые более важные вещи заключаются в том, что changeTurn и WinCombos не являются классами, они являются функциями, поэтому они должны выглядеть как public void changeTurn(){..code..} (void означает, что вы ничего не возвращаете) и public boolean WinCombos(){..code..} (boolean означает, что вы возвращаете логическое значение [true/false]) - person Legion; 12.07.2013
comment
убедитесь, что у вас есть оператор return в WinCombos, который возвращает win. Также должна быть инициализирована restartGame в строке 113, это ActionListener, очень похожий на класс Action, то есть все те же настройки, за исключением того, что он сбрасывает игру в своей собственной функции actionPerformed. У меня была resetGame в качестве глобальной переменной. он был равен new Reset(newgame); - person Legion; 12.07.2013
comment
пожалуйста, также не забудьте выбрать мой ответ! - person Legion; 12.07.2013
comment
Эй, чувак, спасибо тебе за всю твою помощь. Мне нравится, что сообщество программистов так дружелюбно относится к новичкам :) В настоящее время я чувствую себя немного лучше, но все еще есть некоторые проблемы - когда я нажимаю кнопки, ничего не происходит. Я забыл важный фрагмент кода?! Pastebin - person Sphyxx; 14.07.2013
comment
Я только что протестировал код, который у вас есть, и он отлично работает для меня ... единственные изменения, которые я сделал, это добавить финальную } и поместить переменную выигрышных линий внутри actionPerformed. - person Legion; 15.07.2013
comment
Это последняя версия, в которой я протестировал ваш код как NoughtsCrosess. Окончательная версия, которую я создал лично, это NoughtsCrosses. - person Legion; 15.07.2013

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

person nick    schedule 11.07.2013
comment
OP говорит, что каждая кнопка имеет свой собственный текст, который устанавливается на X или O при нажатии каждым игроком. Это может означать, что вы правы, и проблема связана с одной из ненажатых кнопок. - person rossum; 12.07.2013
comment
@rossum да, это в сочетании с java.lang.NullPointerException вселяет в меня уверенность, что проблема в этом. - person nick; 12.07.2013

Похоже, ваша проверка условия победы находится не в вашем коде actionPerformed, а на уровне класса, поэтому, возможно, она вызывается до того, как окно будет заполнено вашими кнопками.

Попробуйте разместить галочку внутри actionPerformed следующим образом: http://pastebin.com/xRViSUzy

person tfoo    schedule 11.07.2013

Какова область (просто говоря, фигурные скобки) внутри проблемной строки?

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

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

Надеюсь, это поможет.

person tuckermi    schedule 11.07.2013

Если вы собираетесь реализовать такое решение, то упростите себе работу. Судя по крошечному фрагменту кода, который я вижу выше, похоже, что вы действительно слишком усложняете работу, которую должны выполнять.

char cell0 = //get that char, be it X or O
char cell1 = //
...
char cell8 = //

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

0 1 2
3 4 5
6 7 8

Так что можно просто идти по порядку:

Horizontal Solutions:
(cell0 == cell1 && cell0 == cell2)
(cell3 == cell4 && cell3 == cell5)
(cell6 == cell7 && cell6 == cell8)

Vertical Solutions
(cell0 == cell3 && cell0 == cell6)
//And so on

Cross Solutions:
(cell0 == cell4 && cell0 == cell8)
(cell2 == cell4 && cell2 == cell6)

Это проверит ваше условие победы.

person Kon    schedule 11.07.2013

Проблема в том, что у вас в коде избыток фигурных скобок, так что операторы в вопросе фактически появляются в блоке инициализатора экземпляра класса NoughtsCrosses, но ни один из компонентов JButton еще не был инициализирован, поскольку инициализаторы экземпляра вызываются до конструкторы, в которых экземпляры JButton существуют (но никогда не вызываются). Когда вы пытаетесь вызвать getText для первого элемента массива square, выдается NullPointerException.

Чтобы исправить, удалите дополнительные фигурные скобки, чтобы код был заключен в предыдущий ActionListener

class Action implements ActionListener {
    public void actionPerformed(ActionEvent e) {
       // existing code here
/// }    remove
//}      remove
// {     remove

    // win conditions. if true, set win==true; else set win
    // here is where the compilation error is, next line
    if (square[0].getText() == square[1].getText() ...) { 
      win = true;
    } //etc
} <-- add this
person Reimeus    schedule 11.07.2013
comment
Благодарю вас! Только что избавился от тех. Теперь он загружается нормально, есть еще одна или две ошибки, но, по крайней мере, я могу видеть, что происходит сейчас, и начать заботиться об этом. Еще раз спасибо :) - person Sphyxx; 12.07.2013