teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

GitHub リンク追加

2021/09/07 16:23

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -284,4 +284,12 @@
284
284
  }
285
285
  }
286
286
  }
287
- ```
287
+ ```
288
+
289
+ ----
290
+
291
+ 弄ってみたコードを GitHub に入れています。
292
+
293
+ [https://github.com/Jimbe-github/teratail_java/tree/master/workspace2/teratail_java/src/teratail_java/q357803](https://github.com/Jimbe-github/teratail_java/tree/master/workspace2/teratail_java/src/teratail_java/q357803)
294
+
295
+ C.java はオリジナル、C2.java は GameFrame.java から出した Turtle.java を使って C.java の構造を変えずに番号追加(ついでに点線や繰り返し部分を修正)、GameFrame.java は…まぁこちらのより弄っています ^^;;;

3

文字表示位置計算、50や9の変数化、亀さん修正など

2021/09/07 16:23

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -1,19 +1,14 @@
1
1
  取り敢えず描画のみ似せて見ました。
2
2
  各マスやイベントをクラスにしたり、点線も専用クラスにしています。
3
3
  各イベントの座標に制限が有るのか無いのかコードから良く分からなかったので、全体を対象にしています。
4
- マスの大きさであるとか文字の位置だとかあちこちに直接数値が書いてありますので、私としてはまだ考える余地のあるコードです。
5
4
 
5
+ 動かした見た目は殆ど変わらないのに、コードは修正の度に長く…。
6
+
6
7
  ```java
7
8
  package teratail_java.q357803;
8
9
 
9
- import java.awt.BasicStroke;
10
- import java.awt.Color;
10
+ import java.awt.*;
11
- import java.awt.Dimension;
12
- import java.awt.Graphics;
13
- import java.awt.Graphics2D;
11
+ import java.awt.geom.Rectangle2D;
14
- import java.awt.GridBagConstraints;
15
- import java.awt.GridBagLayout;
16
- import java.awt.Point;
17
12
  import java.util.ArrayList;
18
13
  import java.util.List;
19
14
  import java.util.Random;
@@ -42,7 +37,7 @@
42
37
  gbc.gridwidth = 1;
43
38
  gbc.gridheight = 1;
44
39
  gbc.anchor = GridBagConstraints.CENTER;
45
- add(new GamePanel(), gbc); //描画領域の追加
40
+ add(new GamePanel(50, 9), gbc); //描画領域の追加
46
41
  }
47
42
 
48
43
  //マス
@@ -50,26 +45,23 @@
50
45
  enum Direction {
51
46
  CENTER, EAST, WEST, NORTH, SOUTH;
52
47
  }
53
- final int number, x, y;
48
+ private int number, x, y;
54
- final int gx, gy, size;
49
+ private int gx, gy, size;
55
- private Color background;
50
+ private Color background = new Color(0, 170, 0);
56
51
  private Event event;
57
- Square(int number, int x, int y) {
52
+ Square(int number, int x, int y, int size) {
58
53
  this.number = number;
59
54
  this.x = x;
60
55
  this.y = y;
56
+ this.size = size;
57
+
61
- this.gx = x * 50;
58
+ this.gx = x * size;
62
- this.gy = y * 50;
59
+ this.gy = y * size;
63
- this.size = 50;
64
- this.background = new Color(0, 170, 0);
65
60
  }
66
- void setEvent(Event event) {
61
+ void setEvent(Event event) { this.event = event; }
67
- this.event = event;
68
- }
69
62
  //イベントがあるか
70
- boolean hasEvent() {
71
- return event != null;
63
+ boolean hasEvent() { return event != null; }
72
- }
64
+ //マスの各方向の座標
73
65
  Point getPoint(Direction dir) {
74
66
  switch(dir) {
75
67
  case EAST:
@@ -91,9 +83,17 @@
91
83
  g2.dispose();
92
84
 
93
85
  g.drawRect(gx, gy, size, size); //枠
86
+
94
- g.drawString(""+number, gx+size-15, gy+size-5); //番号
87
+ drawStringAtBottomRight(g, ""+number); //番号
95
- if(hasEvent()) event.draw(g, gx+5, gy+5+10); //イベント
88
+ if(hasEvent()) event.draw(g, gx+2, gy+2); //イベント
96
89
  }
90
+ private void drawStringAtBottomRight(Graphics g, String text) {
91
+ FontMetrics fm = g.getFontMetrics();
92
+ int descent = fm.getDescent(); //ベースラインの高さ
93
+ Rectangle2D rect = fm.getStringBounds(text, g);
94
+ int width = (int)rect.getWidth(); //文字列の幅
95
+ g.drawString(text, gx+size-width-1, gy+size-descent-1); //-1 はちょっと隙間
96
+ }
97
97
  }
98
98
 
99
99
  //イベント
@@ -107,8 +107,14 @@
107
107
  this.text2 = text2;
108
108
  }
109
109
  void draw(Graphics g, int gx, int gy) {
110
+ FontMetrics fm = g.getFontMetrics();
111
+ gy += fm.getAscent(); //ベースラインから文字頂までの高さ
110
112
  g.drawString(text1, gx, gy);
113
+ if(text2 != null) {
114
+ Rectangle2D rect = fm.getStringBounds(text2, g);
115
+ gy += (int)rect.getHeight();
111
- if(text2 != null) g.drawString(text2, gx, gy+13);
116
+ g.drawString(text2, gx, gy);
117
+ }
112
118
  }
113
119
  }
114
120
 
@@ -135,15 +141,19 @@
135
141
  }
136
142
  }
137
143
 
138
- //亀さん
144
+ //右好きの亀さん
139
145
  private static class Turtle {
146
+ interface Confirm {
147
+ //安全確認. x,y にマイナスや大きな値が入っても例外を出さないよう注意.
148
+ boolean isSafe(int x, int y);
149
+ }
140
150
  enum Direction {
141
151
  NORTH(0,-1) { Direction right() { return EAST; } },
142
152
  SOUTH(0, 1) { Direction right() { return WEST; } },
143
153
  EAST( 1,0) { Direction right() { return SOUTH; } },
144
154
  WEST(-1,0) { Direction right() { return NORTH; } };
145
155
 
146
- int dx, dy;
156
+ final int dx, dy;
147
157
  Direction(int dx, int dy) {
148
158
  this.dx = dx;
149
159
  this.dy = dy;
@@ -152,33 +162,36 @@
152
162
  }
153
163
  private int x, y;
154
164
  private Direction dir;
165
+ private Confirm confirm;
155
- Turtle(int x, int y, Direction dir) {
166
+ Turtle(int x, int y, Direction dir, Confirm confirm) {
156
167
  this.x = x;
157
168
  this.y = y;
158
169
  this.dir = dir;
170
+ this.confirm = confirm;
159
171
  }
172
+ int getX() { return x; }
173
+ int getY() { return y; }
160
- Point forward() {
174
+ void forward() {
161
175
  x += dir.dx;
162
176
  y += dir.dy;
163
- return new Point(x, y);
177
+ Direction sence = dir.right(); //この辺が右好き
178
+ if(confirm.isSafe(x+sence.dx, y+sence.dy)) dir = sence;
164
179
  }
165
- Point getRightPoint() {
166
- Direction right = dir.right();
167
- return new Point(x+right.dx, y+right.dy);
168
- }
169
- void turnRight() {
170
- dir = dir.right();
171
- }
172
180
  }
173
181
 
174
182
  //描画する紙を表すクラス
175
183
  private static class GamePanel extends JPanel {
176
184
  private List<Square> squareList = new ArrayList<>(); //中心を index=0 とし、螺旋を展開した直線状態
177
185
  private Random random = new Random();
186
+ private final int square_size;
187
+ private final int square_count;
178
188
 
179
- GamePanel() {
189
+ GamePanel(int square_size, int square_count) {
180
190
  super(null);
191
+ this.square_size = square_size;
192
+ this.square_count = square_count;
193
+
181
- setPreferredSize(new Dimension(50*9+50, 50*9));
194
+ setPreferredSize(new Dimension(square_size*(square_count+1), square_size*square_count));
182
195
  setMinimumSize(getPreferredSize());
183
196
 
184
197
  initSquareList();
@@ -198,19 +211,16 @@
198
211
 
199
212
  //マス準備
200
213
  private void initSquareList() {
201
- int i = 0;
202
- squareList.add(new Square(i+1, 4, 4));
203
- Turtle t = new Turtle(4, 4, Turtle.Direction.EAST);
214
+ Turtle turtle = new Turtle(square_count/2, square_count/2, Turtle.Direction.EAST, new Turtle.Confirm() {
204
- for(i++ ; i<9*9; i++) {
205
- Point point = t.forward();
215
+ @Override
206
- squareList.add(new Square(i+1, point.x, point.y));
216
+ public boolean isSafe(int x, int y) {
217
+ for(Square s : squareList) if(s.x == x && s.y == y) return false; //既に通った
218
+ return true;
219
+ }
220
+ });
207
221
 
208
- Point right = t.getRightPoint();
209
- boolean found = false;
210
- for(Square s : squareList) {
222
+ for(int number=1; number<=square_count*square_count; turtle.forward(), number++) {
211
- if(found = (s.x == right.x && s.y == right.y)) break;
223
+ squareList.add(new Square(number, turtle.getX(), turtle.getY(), square_size));
212
- }
213
- if(!found) t.turnRight(); //右に進めるなら右に曲がる
214
224
  }
215
225
  }
216
226
 
@@ -239,7 +249,7 @@
239
249
 
240
250
  //ランダムにマスを選択
241
251
  private Square getRandomSquare() {
242
- return getRandomSquare(9,0,9,0);
252
+ return getRandomSquare(square_count,0,square_count,0);
243
253
  }
244
254
  private Square getRandomSquare(int xbound, int xoffset, int ybound, int yoffset) {
245
255
  int x = random.nextInt(xbound) + xoffset;
@@ -248,9 +258,7 @@
248
258
  }
249
259
  //x,y指定から Square を得る
250
260
  private Square getSquare(int x, int y) {
251
- for(Square s : squareList) {
252
- if(s.x == x && s.y == y) return s;
261
+ for(Square s : squareList) if(s.x == x && s.y == y) return s;
253
- }
254
262
  return null;
255
263
  }
256
264
 
@@ -259,9 +267,9 @@
259
267
 
260
268
  //ゴール
261
269
  g.setColor(Color.yellow);
262
- g.fillRect(50*9, 0, 50, 50);
270
+ g.fillRect(square_size*square_count, 0, square_size, square_size);
263
271
  g.setColor(Color.black);
264
- g.drawString("ゴール", 50*9+5, 13);
272
+ g.drawString("ゴール", square_size*square_count+5, 13);
265
273
 
266
274
  //各マス
267
275
  for(Square s : squareList) s.draw(g);
@@ -269,8 +277,8 @@
269
277
  //点線
270
278
  DotLineDrawer dotLineDrawer = new DotLineDrawer(5);
271
279
  dotLineDrawer.setStart(squareList.get(0).getPoint(Square.Direction.CENTER));
272
- for(int i=1; i<squareList.size()-1; i++) {
280
+ for(Square s : squareList.subList(1, squareList.size()-1)) {
273
- dotLineDrawer.draw(g, squareList.get(i).getPoint(Square.Direction.CENTER));
281
+ dotLineDrawer.draw(g, s.getPoint(Square.Direction.CENTER));
274
282
  }
275
283
  dotLineDrawer.draw(g, squareList.get(squareList.size()-1).getPoint(Square.Direction.EAST)); //最後はマスの右端まで
276
284
  }

2

点線を BasicStroke 使用に変更、螺旋化を亀さん使用に変更。

2021/09/05 18:20

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -6,12 +6,16 @@
6
6
  ```java
7
7
  package teratail_java.q357803;
8
8
 
9
+ import java.awt.BasicStroke;
9
10
  import java.awt.Color;
10
11
  import java.awt.Dimension;
11
12
  import java.awt.Graphics;
13
+ import java.awt.Graphics2D;
12
14
  import java.awt.GridBagConstraints;
13
15
  import java.awt.GridBagLayout;
14
16
  import java.awt.Point;
17
+ import java.util.ArrayList;
18
+ import java.util.List;
15
19
  import java.util.Random;
16
20
 
17
21
  import javax.swing.JFrame;
@@ -46,12 +50,14 @@
46
50
  enum Direction {
47
51
  CENTER, EAST, WEST, NORTH, SOUTH;
48
52
  }
49
- private int number;
53
+ final int number, x, y;
50
- private int gx, gy, size;
54
+ final int gx, gy, size;
51
55
  private Color background;
52
56
  private Event event;
53
57
  Square(int number, int x, int y) {
54
58
  this.number = number;
59
+ this.x = x;
60
+ this.y = y;
55
61
  this.gx = x * 50;
56
62
  this.gy = y * 50;
57
63
  this.size = 50;
@@ -108,51 +114,66 @@
108
114
 
109
115
  //点線描画
110
116
  private static class DotLineDrawer {
111
- private int count;
112
117
  private int x, y;
113
- private int solid_period;
118
+ private BasicStroke dashed;
114
- private int pattern_length;
115
- DotLineDrawer(int solid_period, int space_period) {
119
+ DotLineDrawer(int solid_period) {
116
- this.solid_period = solid_period;
117
- this.pattern_length = solid_period + space_period;
120
+ dashed = new BasicStroke(0, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{solid_period}, 0);
118
121
  }
119
122
  //始点
120
123
  void setStart(Point start) {
121
- count = 0;
122
124
  x = start.x;
123
125
  y = start.y;
124
126
  }
125
127
  //始点もしくは最後に draw した後から描画
126
128
  void draw(Graphics g, Point end) {
127
- if(x != end.x) { //横線?
129
+ Graphics2D g2 = (Graphics2D)g.create();
130
+ g2.setStroke(dashed);
128
- int dx = (int)Math.signum(end.x - x);
131
+ g2.drawLine(x, y, end.x, end.y);
129
- for( ; x!=end.x; x+=dx, count=(count+1)%pattern_length) {
130
- if(count < solid_period) g.drawRect(x, y, 0, 0);
132
+ g2.dispose();
133
+ x = end.x;
134
+ y = end.y;
131
- }
135
+ }
132
- } else { //縦線
133
- int dy = (int)Math.signum(end.y - y);
134
- for( ; y!=end.y; y+=dy, count=(count+1)%pattern_length) {
135
- if(count < solid_period) g.drawRect(x, y, 0, 0);
136
- }
136
+ }
137
+
138
+ //亀さん
139
+ private static class Turtle {
140
+ enum Direction {
141
+ NORTH(0,-1) { Direction right() { return EAST; } },
142
+ SOUTH(0, 1) { Direction right() { return WEST; } },
143
+ EAST( 1,0) { Direction right() { return SOUTH; } },
144
+ WEST(-1,0) { Direction right() { return NORTH; } };
145
+
146
+ int dx, dy;
147
+ Direction(int dx, int dy) {
148
+ this.dx = dx;
149
+ this.dy = dy;
137
150
  }
151
+ abstract Direction right();
138
152
  }
153
+ private int x, y;
154
+ private Direction dir;
155
+ Turtle(int x, int y, Direction dir) {
156
+ this.x = x;
157
+ this.y = y;
158
+ this.dir = dir;
159
+ }
160
+ Point forward() {
161
+ x += dir.dx;
162
+ y += dir.dy;
163
+ return new Point(x, y);
164
+ }
165
+ Point getRightPoint() {
166
+ Direction right = dir.right();
167
+ return new Point(x+right.dx, y+right.dy);
168
+ }
169
+ void turnRight() {
170
+ dir = dir.right();
171
+ }
139
172
  }
140
173
 
141
174
  //描画する紙を表すクラス
142
175
  private static class GamePanel extends JPanel {
143
- //螺旋座標
144
- private static final int POINTS[] = {
145
- 4,4, 5,4, 5,5, 4,5, 3,5, 3,4, 3,3, 4,3, 5,3,
146
- 6,3, 6,4, 6,5, 6,6, 5,6, 4,6, 3,6, 2,6, 2,5,
147
- 2,4, 2,3, 2,2, 3,2, 4,2, 5,2, 6,2, 7,2, 7,3,
148
- 7,4, 7,5, 7,6, 7,7, 6,7, 5,7, 4,7, 3,7, 2,7,
149
- 1,7, 1,6, 1,5, 1,4, 1,3, 1,2, 1,1, 2,1, 3,1,
150
- 4,1, 5,1, 6,1, 7,1, 8,1, 8,2, 8,3, 8,4, 8,5,
151
- 8,6, 8,7, 8,8, 7,8, 6,8, 5,8, 4,8, 3,8, 2,8,
152
- 1,8, 0,8, 0,7, 0,6, 0,5, 0,4, 0,3, 0,2, 0,1,
153
- 0,0, 1,0, 2,0, 3,0, 4,0, 5,0, 6,0, 7,0, 8,0
154
- };
155
- private Square squares[] = new Square[9*9]; //中心を [0] とし、螺旋を展開した直線状態
176
+ private List<Square> squareList = new ArrayList<>(); //中心を index=0 とし、螺旋を展開した直線状態
156
177
  private Random random = new Random();
157
178
 
158
179
  GamePanel() {
@@ -160,11 +181,10 @@
160
181
  setPreferredSize(new Dimension(50*9+50, 50*9));
161
182
  setMinimumSize(getPreferredSize());
162
183
 
163
- for(int number=1, i=0, j=0; number<=9*9; number++, i++, j+=2) {
164
- squares[i] = new Square(number, POINTS[j], POINTS[j+1]);
184
+ initSquareList();
165
- }
166
- squares[0].setEvent(new Event("スタート"));
167
185
 
186
+ squareList.get(0).setEvent(new Event("スタート"));
187
+
168
188
  setForwardingEvent(); //"進む"イベント(1)
169
189
  setRotateEvent("⤵ 90°"); //盤面回転イベント(1)
170
190
  setForwardingEvent(); //"進む"イベント(2)
@@ -176,6 +196,24 @@
176
196
  setForwardingEvent(); //"進む"イベント(6)
177
197
  }
178
198
 
199
+ //マス準備
200
+ private void initSquareList() {
201
+ int i = 0;
202
+ squareList.add(new Square(i+1, 4, 4));
203
+ Turtle t = new Turtle(4, 4, Turtle.Direction.EAST);
204
+ for(i++ ; i<9*9; i++) {
205
+ Point point = t.forward();
206
+ squareList.add(new Square(i+1, point.x, point.y));
207
+
208
+ Point right = t.getRightPoint();
209
+ boolean found = false;
210
+ for(Square s : squareList) {
211
+ if(found = (s.x == right.x && s.y == right.y)) break;
212
+ }
213
+ if(!found) t.turnRight(); //右に進めるなら右に曲がる
214
+ }
215
+ }
216
+
179
217
  //"進む"イベント
180
218
  private void setForwardingEvent() {
181
219
  Square square = getRandomSquare();
@@ -210,8 +248,8 @@
210
248
  }
211
249
  //x,y指定から Square を得る
212
250
  private Square getSquare(int x, int y) {
213
- for(int i=0; i<POINTS.length; i+=2) {
251
+ for(Square s : squareList) {
214
- if(POINTS[i] == x && POINTS[i+1] == y) return squares[i/2];
252
+ if(s.x == x && s.y == y) return s;
215
253
  }
216
254
  return null;
217
255
  }
@@ -226,17 +264,15 @@
226
264
  g.drawString("ゴール", 50*9+5, 13);
227
265
 
228
266
  //各マス
229
- for(int i=0; i<squares.length; i++) {
230
- squares[i].draw(g);
267
+ for(Square s : squareList) s.draw(g);
231
- }
232
268
 
233
269
  //点線
234
- DotLineDrawer dotLineDrawer = new DotLineDrawer(5,5);
270
+ DotLineDrawer dotLineDrawer = new DotLineDrawer(5);
235
- dotLineDrawer.setStart(squares[0].getPoint(Square.Direction.CENTER));
271
+ dotLineDrawer.setStart(squareList.get(0).getPoint(Square.Direction.CENTER));
236
- for(int i=1; i<squares.length-1; i++) {
272
+ for(int i=1; i<squareList.size()-1; i++) {
237
- dotLineDrawer.draw(g, squares[i].getPoint(Square.Direction.CENTER));
273
+ dotLineDrawer.draw(g, squareList.get(i).getPoint(Square.Direction.CENTER));
238
274
  }
239
- dotLineDrawer.draw(g, squares[squares.length-1].getPoint(Square.Direction.EAST)); //最後はマスの右端まで
275
+ dotLineDrawer.draw(g, squareList.get(squareList.size()-1).getPoint(Square.Direction.EAST)); //最後はマスの右端まで
240
276
  }
241
277
  }
242
278
  }

1

getSquare 修正

2021/09/05 13:33

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -210,7 +210,10 @@
210
210
  }
211
211
  //x,y指定から Square を得る
212
212
  private Square getSquare(int x, int y) {
213
+ for(int i=0; i<POINTS.length; i+=2) {
214
+ if(POINTS[i] == x && POINTS[i+1] == y) return squares[i/2];
215
+ }
213
- return squares[y*9+x];
216
+ return null;
214
217
  }
215
218
 
216
219
  public void paintComponent(Graphics g) {