Advertisement
Guest User

Untitled

a guest
Aug 18th, 2019
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.17 KB | None | 0 0
  1. import java.util.stream.Collectors;
  2. import java.util.stream.IntStream;
  3. import java.awt.event.*;
  4. import javax.swing.*;
  5. import java.util.*;
  6. /**This program uses GUI, including a JTextField. Both javax.swing.* and java.awt.event.* need to be imported in this program.
  7. *This program also uses java.util.*
  8. */
  9. public class ConnectFour {
  10. private static final char[] players = new char[] { 'X', 'O' };
  11.  
  12. private final int width, height;
  13.  
  14. private int lastCol = -1, lastTop = -1;
  15.  
  16. private GUI gui=new GUI(); //The GUI class needs to be used in the ConnectFour class to have GUI for this game.
  17.  
  18. final char[][] grid;
  19.  
  20.  
  21. public ConnectFour(int width, int height) {
  22. this.width = width;
  23. this.height = height;
  24. this.grid = new char[height][];
  25. for (int h = 0; h < height; h++) {
  26. Arrays.fill(this.grid[h] = new char[width], '.');
  27. }
  28. }
  29.  
  30. public String toString() {
  31. return IntStream.range(0, this.width)
  32. .mapToObj(Integer::toString)
  33. .collect(Collectors.joining()) + "n" +
  34. Arrays.stream(this.grid)
  35. .map(String::new)
  36. .collect(Collectors.joining("n"));
  37. }
  38.  
  39. /**
  40. * Prompts the user for a column, repeating until a valid
  41. * choice is made.
  42. */
  43. public void chooseAndDrop(char symbol) {
  44. //This string variable is used by a label to give details on whether a user entered a valid column number or not.
  45. String columnInfo="";
  46. do {
  47. /**The chooseAndDrop GUI will update two labels to display important information to the user(s).
  48. * It will tell the user(s) whether Player X or Player O is supposed to play and also if a
  49. * valid column number was entered by the users.
  50. */
  51. gui.chooseAndDropGUI(symbol, columnInfo);
  52. int col = gui.readPlayerInputForProcessing();
  53. columnInfo="";
  54. if (! (0 <= col && col < this.width)) {
  55. /**If a user entered a column number that is outside of the accepted range,
  56. * the columnInfo variable is updated to tell the user to pick a column
  57. * in the accepted range.
  58. */
  59. columnInfo="Column must be between 0 and " +
  60. (this.width - 1);
  61. continue;
  62. }
  63. for (int h = this.height - 1; h >= 0; h--) {
  64. if (this.grid[h][col] == '.') {
  65. this.grid[this.lastTop=h][this.lastCol=col] = symbol;
  66. return;
  67. }
  68. }
  69. /**If a user entered in a column number and that column is already full,
  70. * the columnInfo variable is updated to tell the user to pick a different column.
  71. */
  72. columnInfo="Column "+col+" is full.";
  73.  
  74. }while (true);
  75. }
  76.  
  77. /**
  78. * Detects whether the last chip played was a winning move.
  79. */
  80. public boolean isWinningPlay() {
  81. char sym = this.grid[this.lastTop][this.lastCol];
  82. String streak = String.format("%c%c%c%c", sym, sym, sym, sym);
  83. return contains(this.horizontal(), streak) ||
  84. contains(this.vertical(), streak) ||
  85. contains(this.slashDiagonal(), streak) ||
  86. contains(this.backslashDiagonal(), streak);
  87. }
  88.  
  89. /**
  90. * The contents of the row containing the last played chip.
  91. */
  92. private String horizontal() {
  93. return new String(this.grid[this.lastTop]);
  94. }
  95.  
  96. /**
  97. * The contents of the column containing the last played chip.
  98. */
  99. private String vertical() {
  100. StringBuilder sb = new StringBuilder(this.height);
  101. for (int h = 0; h < this.height; h++) {
  102. sb.append(this.grid[h][this.lastCol]);
  103. }
  104. return sb.toString();
  105. }
  106.  
  107. /**
  108. * The contents of the "/" diagonal containing the last played chip
  109. * (coordinates have a constant sum).
  110. */
  111. private String slashDiagonal() {
  112. StringBuilder sb = new StringBuilder(this.height);
  113. for (int h = 0; h < this.height; h++) {
  114. int w = this.lastCol + this.lastTop - h;
  115. if (0 <= w && w < this.width) {
  116. sb.append(this.grid[h][w]);
  117. }
  118. }
  119. return sb.toString();
  120. }
  121.  
  122. /**
  123. * The contents of the "" diagonal containing the last played chip
  124. * (coordinates have a constant difference).
  125. */
  126. private String backslashDiagonal() {
  127. StringBuilder sb = new StringBuilder(this.height);
  128. for (int h = 0; h < this.height; h++) {
  129. int w = this.lastCol - this.lastTop + h;
  130. if (0 <= w && w < this.width) {
  131. sb.append(this.grid[h][w]);
  132. }
  133. }
  134. return sb.toString();
  135. }
  136.  
  137. private static boolean contains(String haystack, String needle) {
  138. return haystack.indexOf(needle) >= 0;
  139. }
  140.  
  141. public static void main(String[] args) {
  142. int height = 6, width = 8, moves = height * width;
  143. ConnectFour board = new ConnectFour(width, height);
  144. /**The emptyChar char is used for the first time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
  145. *is called. This is because no specific char value is needed for the first time this function is called. Due to the number in the first parameter,
  146. *this function sets the text of a label to tell the user(s) the acceptable range an inputed column number is supposed to be in.
  147. */
  148. char emptyChar=' ';
  149. board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(2,width,emptyChar);
  150. //Since the board does not already exist, the last parameter is set to false to create a new empty board.
  151. board.gui.createBoard(width, height, board, false);
  152. for (int player = 0; moves-- > 0; player = 1 - player) {
  153. char symbol = players[player];
  154. board.chooseAndDrop(symbol);
  155. //Since the board already does exist, the last parameter is set to true to update the existing board.
  156. board.gui.createBoard(width, height, board, true);
  157. if (board.isWinningPlay()) {
  158. /**The symbol char is used for the second time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
  159. *is called. Due to the number in the first parameter, this function will tell which player won. The symbol of the player who
  160. *won (X or O) is stored in the symbol char. Therefore, the symbol char is used to tell which player won.
  161. */
  162. board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(1,width,symbol);
  163. return;
  164. }
  165. }
  166. /**The empty char is used for the third time the function label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function
  167. *is called. This is because no specific char value is needed for the third time this function is called. Due to the number in the first parameter,
  168. *this function sets the text of a label to tell the user(s) that nobody has won.
  169. */
  170. board.gui.label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(0,width,emptyChar);
  171. }
  172. }
  173. //This class GUI is used to create GUI for the game.
  174. class GUI{
  175.  
  176. private static JFrame jframe; //This variable is used to create a JFrame window.
  177. private static List<JLabel> boardLabels; //This list is used to store a group of labels related to the board's graphics.
  178. private static JLabel labelDisplayingWhosTurnItIs;
  179. private static JLabel labelTellingDetailsRegardingColumns;
  180. private static JLabel labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon;
  181. private final int defaultLabelWidth=100;
  182. private final int defaultLabelHeight=100;
  183. private final int lengthyLabelsWidth=400; //This width is used for labels that have a long width
  184. private final int defaultTextFieldWidth=200;
  185. private final int defaultTextFieldHeight=50;
  186. //The initial x coordinate for each label in the board's graphics is multiplied by this value to add spacing among each label in the board's graphics.
  187. private final int xScaling=50;
  188. //The initial y coordinate for each label in the board's graphics is multiplied by this value to add spacing among each label in the board's graphics.
  189. private final int yScaling=50;
  190. //After being multiplied, the x coordinate is added with xOffset to translate it to the right a little bit.
  191. private final int xOffset=50;
  192. //After being multiplied, the y coordinate is added with yOffset to translate it up a little bit.
  193. private final int yOffset=100;
  194. //The two variables below are used to set the size of the JFrame.
  195. private final int screenXSize=500;
  196. private final int screenYSize=900;
  197. //When a user presses the Enter key inside the text field, this variable is set to true.
  198. private static boolean inputReadyForProcessing=false;
  199. //This is the text field where input is entered by the player.
  200. private static JTextField playerInput=new JTextField("");
  201.  
  202. public GUI() {
  203. /** A basic GUI window is created, and variables are initialized.
  204. * GUI elements are positioned in coordinates by setBounds
  205. * and are added to the JFrame window.
  206. */
  207. jframe=new JFrame();
  208. boardLabels=new ArrayList<JLabel>();
  209. jframe.setVisible(true);
  210. jframe.setSize(screenXSize,screenYSize);
  211. jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  212. jframe.setLayout(null);
  213. jframe.setResizable(false);
  214. labelDisplayingWhosTurnItIs=new JLabel("");
  215. labelDisplayingWhosTurnItIs.setBounds(150,550,defaultLabelWidth,defaultLabelHeight);
  216. labelTellingDetailsRegardingColumns=new JLabel("");
  217. labelTellingDetailsRegardingColumns.setBounds(150,600,lengthyLabelsWidth, defaultLabelHeight);
  218. labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon=new JLabel("");
  219. labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setBounds(150,750,lengthyLabelsWidth, defaultLabelHeight);
  220. playerInput.setBounds(125, 700, defaultTextFieldWidth, defaultTextFieldHeight);
  221. jframe.add(labelDisplayingWhosTurnItIs);
  222. jframe.add(labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon);
  223. jframe.add(labelTellingDetailsRegardingColumns);
  224. jframe.add(playerInput);
  225.  
  226. /**An ActionListener is added to the text field variable. Whenever a player presses the Enter key inside this text field,
  227. * an action will be performed. In this case, inputReadyForProcessing is set to true, which will be useful in this program.
  228. */
  229. playerInput.addActionListener(new ActionListener() {
  230. public void actionPerformed(ActionEvent e) {
  231. inputReadyForProcessing=true;
  232. }
  233. });
  234. }
  235.  
  236. //This function can both be used to create a new empty board and to update an existing board.
  237. public void createBoard(int width, int height, ConnectFour board, boolean updateExsistingBoard) {
  238. int indexOfLabel=0;
  239. for(int x=0; x<width; x++) {
  240. for(int y=0; y<height; y++) {
  241. /** Labels are set to the string variable slotLabelString.
  242. * This string variable adds a char to an empty string, which makes it
  243. * basically equal to a string version of the char. This variable
  244. * stores the value of a point in the grid array. This value is used
  245. * to set each label equal to its corresponding point in the grid array.
  246. * The grid array is used in the backbone for this program for basic
  247. * game logic.
  248. */
  249. String slotLabelString=board.grid[y][x]+"";
  250. if(updateExsistingBoard) {
  251. //If the board already exists, just update the label's text.
  252. boardLabels.get(indexOfLabel).setText(slotLabelString);
  253. }
  254. else {
  255. //If the board does not already exist, create a new label.
  256. boardLabels.add(new JLabel(slotLabelString));
  257. boardLabels.get(indexOfLabel).setBounds(x*xScaling+xOffset,y*yScaling+yOffset,defaultLabelWidth,defaultLabelHeight);
  258. }
  259. //Each label is added to the JFrame window.
  260. jframe.add(boardLabels.get(indexOfLabel));
  261. indexOfLabel++;
  262. }
  263. }
  264. }
  265.  
  266. //This function can change the text of a specific label.
  267. public void label_That_Tells_Player_What_Columns_They_Can_Pick_Or_Tells_Them_Who_Won_Function(int did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw, int width, char symbol) {
  268. if (did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw==1) {
  269. labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Player " + symbol + " wins!");
  270. }
  271. else if (did_Someone_Win_One_For_Yes_Two_For_No_Other_For_Draw==2) {
  272. labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Use 0-" + (width - 1) + " to choose a column.");
  273. }
  274. else {
  275. labelThatTellsPlayerWhatColumnsTheyCanPickOrTellsThemWhoWon.setText("Game over, no winner.");
  276. }
  277.  
  278. }
  279.  
  280. /**This function is used to return the integer version of the string entered in the text field.
  281. *This function is called in the chooseAndDropGUI from the ConnectFour class.
  282. */
  283. public int readPlayerInputForProcessing()
  284. {
  285. while(true)
  286. {
  287. int playerInputValue;
  288.  
  289. /**If a player entered an input that is not a number, trying to convert it into an integer would result in errors.
  290. * Therefore, the try and catch method is used.
  291. */
  292. try
  293. {
  294. playerInputValue=Integer.valueOf(playerInput.getText());
  295. }
  296.  
  297. catch(Exception err)
  298. {
  299. //If an error is caused, the program goes back to the beginning of the while loop.
  300. continue;
  301. }
  302.  
  303. /**This if statement is intentionally not the first if statement in the function.
  304. *This allows the function to have some time to process if whether inputReadyForProcessing is equal to true or not.
  305. *This variable is equal to true only if an Enter key was pressed in the text field. Therefore, the playerInputValue
  306. *is only returned when a user presses the Enter key. Otherwise, the program goes back to the beginning of the while loop.
  307. */
  308. if(!inputReadyForProcessing)
  309. {
  310. continue;
  311. }
  312. /** This variable is set back to its initial state, false. To make this variable true again, the Enter key will have to be
  313. * pressed inside the text field once again. This makes the program only return numerical input inside the text field only when
  314. * the Enter key is pressed inside the text field.
  315. */
  316. inputReadyForProcessing=false;
  317.  
  318. return playerInputValue;
  319. }
  320. }
  321. /**
  322. * This function is created to create the GUI aspects for the function chooseAndDropGUI in the ConnectFour class.
  323. */
  324. public void chooseAndDropGUI(char symbol, String columnInfo) {
  325. labelDisplayingWhosTurnItIs.setText("nPlayer " + symbol + " turn: ");
  326. labelTellingDetailsRegardingColumns.setText(columnInfo);
  327. }
  328.  
  329. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement