console-shogi 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +19 -0
  4. data/images/active/gote/fu.png +0 -0
  5. data/images/active/gote/gin.png +0 -0
  6. data/images/active/gote/gyoku.png +0 -0
  7. data/images/active/gote/hisha.png +0 -0
  8. data/images/active/gote/kaku.png +0 -0
  9. data/images/active/gote/keima.png +0 -0
  10. data/images/active/gote/kin.png +0 -0
  11. data/images/active/gote/kyosha.png +0 -0
  12. data/images/active/gote/narigin.png +0 -0
  13. data/images/active/gote/narikei.png +0 -0
  14. data/images/active/gote/narikyo.png +0 -0
  15. data/images/active/gote/ohsho.png +0 -0
  16. data/images/active/gote/ryu.png +0 -0
  17. data/images/active/gote/tokin.png +0 -0
  18. data/images/active/gote/uma.png +0 -0
  19. data/images/active/nonepiece.png +0 -0
  20. data/images/active/sente/fu.png +0 -0
  21. data/images/active/sente/gin.png +0 -0
  22. data/images/active/sente/gyoku.png +0 -0
  23. data/images/active/sente/hisha.png +0 -0
  24. data/images/active/sente/kaku.png +0 -0
  25. data/images/active/sente/keima.png +0 -0
  26. data/images/active/sente/kin.png +0 -0
  27. data/images/active/sente/kyosha.png +0 -0
  28. data/images/active/sente/narigin.png +0 -0
  29. data/images/active/sente/narikei.png +0 -0
  30. data/images/active/sente/narikyo.png +0 -0
  31. data/images/active/sente/ohsho.png +0 -0
  32. data/images/active/sente/ryu.png +0 -0
  33. data/images/active/sente/tokin.png +0 -0
  34. data/images/active/sente/uma.png +0 -0
  35. data/images/focused/gote/fu.png +0 -0
  36. data/images/focused/gote/gin.png +0 -0
  37. data/images/focused/gote/gyoku.png +0 -0
  38. data/images/focused/gote/hisha.png +0 -0
  39. data/images/focused/gote/kaku.png +0 -0
  40. data/images/focused/gote/keima.png +0 -0
  41. data/images/focused/gote/kin.png +0 -0
  42. data/images/focused/gote/kyosha.png +0 -0
  43. data/images/focused/gote/narigin.png +0 -0
  44. data/images/focused/gote/narikei.png +0 -0
  45. data/images/focused/gote/narikyo.png +0 -0
  46. data/images/focused/gote/ohsho.png +0 -0
  47. data/images/focused/gote/ryu.png +0 -0
  48. data/images/focused/gote/tokin.png +0 -0
  49. data/images/focused/gote/uma.png +0 -0
  50. data/images/focused/nonepiece.png +0 -0
  51. data/images/focused/sente/fu.png +0 -0
  52. data/images/focused/sente/gin.png +0 -0
  53. data/images/focused/sente/gyoku.png +0 -0
  54. data/images/focused/sente/hisha.png +0 -0
  55. data/images/focused/sente/kaku.png +0 -0
  56. data/images/focused/sente/keima.png +0 -0
  57. data/images/focused/sente/kin.png +0 -0
  58. data/images/focused/sente/kyosha.png +0 -0
  59. data/images/focused/sente/narigin.png +0 -0
  60. data/images/focused/sente/narikei.png +0 -0
  61. data/images/focused/sente/narikyo.png +0 -0
  62. data/images/focused/sente/ohsho.png +0 -0
  63. data/images/focused/sente/ryu.png +0 -0
  64. data/images/focused/sente/tokin.png +0 -0
  65. data/images/focused/sente/uma.png +0 -0
  66. data/lib/console_shogi/board.rb +5 -9
  67. data/lib/console_shogi/game.rb +118 -19
  68. data/lib/console_shogi/komadai.rb +11 -9
  69. data/lib/console_shogi/new_board_builder.rb +41 -41
  70. data/lib/console_shogi/piece.rb +34 -23
  71. data/lib/console_shogi/piece_movement_checker.rb +46 -0
  72. data/lib/console_shogi/piece_mover.rb +31 -48
  73. data/lib/console_shogi/piece_mover_on_komadai.rb +30 -36
  74. data/lib/console_shogi/player.rb +5 -13
  75. data/lib/console_shogi/teban.rb +8 -0
  76. data/lib/console_shogi/terminal/cursor.rb +80 -0
  77. data/lib/console_shogi/terminal/display_area.rb +30 -0
  78. data/lib/console_shogi/terminal/operator.rb +209 -0
  79. data/lib/console_shogi/version.rb +1 -1
  80. data/lib/console_shogi.rb +6 -1
  81. metadata +102 -37
  82. data/images/gote/nonepiece.png +0 -0
  83. data/lib/console_shogi/terminal_operator.rb +0 -211
  84. /data/images/{gote/shori.png → gote_shori.png} +0 -0
  85. /data/images/{gote → nomal/gote}/fu.png +0 -0
  86. /data/images/{gote → nomal/gote}/gin.png +0 -0
  87. /data/images/{gote → nomal/gote}/gyoku.png +0 -0
  88. /data/images/{gote → nomal/gote}/hisha.png +0 -0
  89. /data/images/{gote → nomal/gote}/kaku.png +0 -0
  90. /data/images/{gote → nomal/gote}/keima.png +0 -0
  91. /data/images/{gote → nomal/gote}/kin.png +0 -0
  92. /data/images/{gote → nomal/gote}/kyosha.png +0 -0
  93. /data/images/{gote → nomal/gote}/narigin.png +0 -0
  94. /data/images/{gote → nomal/gote}/narikei.png +0 -0
  95. /data/images/{gote → nomal/gote}/narikyo.png +0 -0
  96. /data/images/{gote → nomal/gote}/ohsho.png +0 -0
  97. /data/images/{gote → nomal/gote}/ryu.png +0 -0
  98. /data/images/{gote → nomal/gote}/tokin.png +0 -0
  99. /data/images/{gote → nomal/gote}/uma.png +0 -0
  100. /data/images/{sente → nomal}/nonepiece.png +0 -0
  101. /data/images/{sente → nomal/sente}/fu.png +0 -0
  102. /data/images/{sente → nomal/sente}/gin.png +0 -0
  103. /data/images/{sente → nomal/sente}/gyoku.png +0 -0
  104. /data/images/{sente → nomal/sente}/hisha.png +0 -0
  105. /data/images/{sente → nomal/sente}/kaku.png +0 -0
  106. /data/images/{sente → nomal/sente}/keima.png +0 -0
  107. /data/images/{sente → nomal/sente}/kin.png +0 -0
  108. /data/images/{sente → nomal/sente}/kyosha.png +0 -0
  109. /data/images/{sente → nomal/sente}/narigin.png +0 -0
  110. /data/images/{sente → nomal/sente}/narikei.png +0 -0
  111. /data/images/{sente → nomal/sente}/narikyo.png +0 -0
  112. /data/images/{sente → nomal/sente}/ohsho.png +0 -0
  113. /data/images/{sente → nomal/sente}/ryu.png +0 -0
  114. /data/images/{sente → nomal/sente}/tokin.png +0 -0
  115. /data/images/{sente → nomal/sente}/uma.png +0 -0
  116. /data/images/{sente/shori.png → sente_shori.png} +0 -0
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'tty-prompt'
5
+
6
+ module ConsoleShogi
7
+ module Terminal
8
+ class Operator
9
+ class << self
10
+ TEBAN = {
11
+ sente: '先手',
12
+ gote: '後手'
13
+ }
14
+
15
+ module EscapeSequence
16
+ RESET = "\e[0m"
17
+ RESET_CURSOR = "\e[1;1H"
18
+ SCREEN_CLEAR = "\e[2J"
19
+ SCREEN_CLEAR_AFTER_CURSOR = "\e[0J"
20
+ OUTSIDE_BOARD = "\e[10;1H"
21
+ CURRENT_POSITION = "\e[6n"
22
+ MOVE_RIGHT_2 = "\e[2C"
23
+ end
24
+
25
+ def cursor
26
+ @cursor ||= Cursor.new
27
+ end
28
+
29
+ def image_height
30
+ @image_height ||= calculate_fit_image_height
31
+ end
32
+
33
+ def clear_scrren
34
+ print EscapeSequence::SCREEN_CLEAR
35
+
36
+ print EscapeSequence::RESET_CURSOR
37
+ end
38
+
39
+ # TODO 駒台の表示方法も考える
40
+ def print_diff_board(previous_board:, board:, sente_komadai:, gote_komadai:)
41
+ print EscapeSequence::RESET_CURSOR
42
+
43
+ board.matrix.row_vectors.each_with_index do |vector, i|
44
+ vector.each_with_index do |piece, j|
45
+ if previous_board.matrix[i, j] == piece
46
+ print EscapeSequence::MOVE_RIGHT_2
47
+ else
48
+ print_image(image: piece.image, height: image_height)
49
+ end
50
+ end
51
+
52
+ print "#{EscapeSequence::RESET}\n"
53
+ end
54
+
55
+ # NOTE 駒台を表示
56
+ print_komadai(komadai: sente_komadai, **DisplayArea::Komadai::Sente::START_INDEX)
57
+ print_komadai(komadai: gote_komadai, **DisplayArea::Komadai::Gote::START_INDEX)
58
+
59
+ # NOTE back a cursor
60
+ back_to_cursor
61
+ end
62
+
63
+ def focus_piece(location:, cursor:)
64
+ piece = location.fetch_piece(x: cursor.squares_position.x, y: cursor.squares_position.y)
65
+
66
+ return if piece.nil?
67
+
68
+ print_image(image: piece.focused_image, height: image_height)
69
+
70
+ back_to_cursor
71
+ end
72
+
73
+ def deactive_piece(location:, previous_cursor:)
74
+ print "\e[#{previous_cursor.terminal_position.y};#{previous_cursor.terminal_position.x}H"
75
+
76
+ piece = location.fetch_piece(x: previous_cursor.squares_position.x, y: previous_cursor.squares_position.y)
77
+
78
+ print_image(image: piece.image, height: image_height) unless piece.nil?
79
+
80
+ back_to_cursor
81
+ end
82
+
83
+ def active_piece(location:, cursor:)
84
+ piece = location.fetch_piece(x: cursor.squares_position.x, y: cursor.squares_position.y)
85
+
86
+ return if piece.nil?
87
+
88
+ print_image(image: piece.active_image, height: image_height)
89
+
90
+ back_to_cursor
91
+ end
92
+
93
+ def select_promotion
94
+ print EscapeSequence::OUTSIDE_BOARD
95
+
96
+ prompt = TTY::Prompt.new
97
+
98
+ prompt.select('成りますか?', show_help: :never) {|menu|
99
+ menu.choice '成る', true
100
+ menu.choice '成らない', false
101
+ }
102
+ end
103
+
104
+ def print_winner(player)
105
+ print "\e[4;7H"
106
+
107
+ print_image(image: player.win_image, height: image_height * 3)
108
+
109
+ print EscapeSequence::OUTSIDE_BOARD
110
+ end
111
+
112
+ # TODO 見た目は後で直す
113
+ def print_teban(teban)
114
+ print EscapeSequence::OUTSIDE_BOARD
115
+ print EscapeSequence::SCREEN_CLEAR_AFTER_CURSOR
116
+
117
+ print "手番 : #{TEBAN[teban.to_sym]}"
118
+
119
+ back_to_cursor
120
+ end
121
+
122
+ private
123
+
124
+ IMAGE_HEIGHT_PIXEL = 240
125
+
126
+ # TODO 無理やりなので、実現方法を再考する
127
+ def calculate_fit_image_height
128
+ start_position = fetch_cursor_position_in_stdin
129
+ # NOTE NonePiece を選んでいることに意味はない
130
+ print_image(image: NonePiece.new.image)
131
+ end_position = fetch_cursor_position_in_stdin
132
+
133
+ fixed_height = IMAGE_HEIGHT_PIXEL / (end_position[1].to_i - start_position[1].to_i)
134
+
135
+ print EscapeSequence::SCREEN_CLEAR
136
+ # NOTE カーソルを1行1列に移動
137
+ print EscapeSequence::RESET_CURSOR
138
+
139
+ fixed_height
140
+ end
141
+
142
+ # TODO view 用の Player 作って整理する
143
+ def print_komadai(komadai:, x:, y:)
144
+ komadai.pieces.row_vectors.each_with_index do |row_pieces, i|
145
+ print "\e[#{y + i};#{x}H"
146
+
147
+ row_pieces.each do |p|
148
+ print_image(image: p.image, height: image_height)
149
+ end
150
+ end
151
+
152
+ print EscapeSequence::RESET
153
+ end
154
+
155
+ # TODO Cursor にも持っているので整理する
156
+ def fetch_cursor_position_in_stdin
157
+ stdout = ''
158
+
159
+ $stdin.raw do |stdin|
160
+ $stdout << EscapeSequence::CURRENT_POSITION
161
+ $stdout.flush
162
+
163
+ # NOTE \e[n;mR という形式で現在位置が返ってくる
164
+ while (c = stdin.getc) != 'R'
165
+ stdout += c
166
+ end
167
+ end
168
+
169
+ stdout.match /(\d+);(\d+)/
170
+ end
171
+
172
+ def back_to_cursor
173
+ print "\e[#{cursor.terminal_position.y};#{cursor.terminal_position.x}H"
174
+ end
175
+
176
+ # TODO 画像を表示するためのメソッド、場所検討
177
+ def print_image(image:, width: nil, height: nil)
178
+ encoded_image = Base64.strict_encode64(image)
179
+
180
+ print_osc
181
+ print "1337;File=inline=1"
182
+ print ";size=#{image.size}"
183
+ print ";name=#{encoded_image}"
184
+ print ";width=#{width}px" unless width.nil?
185
+ print ";height=#{height}px" unless height.nil?
186
+ print ":#{encoded_image}"
187
+ print_st
188
+ end
189
+
190
+ def print_osc
191
+ # NOTE \e] で始まるシーケンスは全てのターミナルで扱えるわけでは無い
192
+ if ENV['TERM'].start_with?('screen') || ENV['TERM'].start_with?('tmux')
193
+ print "\ePtmux;\e\e]"
194
+ else
195
+ print "\e]"
196
+ end
197
+ end
198
+
199
+ def print_st
200
+ if ENV['TERM'].start_with?('screen') || ENV['TERM'].start_with?('tmux')
201
+ print "\a\e\\"
202
+ else
203
+ print "\a"
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConsoleShogi
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/console_shogi.rb CHANGED
@@ -6,11 +6,16 @@ require_relative 'console_shogi/player'
6
6
  require_relative 'console_shogi/board'
7
7
  require_relative 'console_shogi/piece'
8
8
  require_relative 'console_shogi/komadai'
9
+ require_relative 'console_shogi/teban'
10
+
11
+ require_relative 'console_shogi/terminal/display_area'
12
+ require_relative 'console_shogi/terminal/operator'
13
+ require_relative 'console_shogi/terminal/cursor'
9
14
 
10
- require_relative 'console_shogi/terminal_operator'
11
15
  require_relative 'console_shogi/new_board_builder'
12
16
  require_relative 'console_shogi/piece_mover'
13
17
  require_relative 'console_shogi/piece_mover_on_komadai'
18
+ require_relative 'console_shogi/piece_movement_checker'
14
19
 
15
20
  module ConsoleShogi
16
21
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: console-shogi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pekepek
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-24 00:00:00.000000000 Z
11
+ date: 2023-06-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: You can play the Shogi in terminal
14
14
  email:
@@ -24,50 +24,115 @@ files:
24
24
  - README.md
25
25
  - Rakefile
26
26
  - exe/console-shogi
27
- - images/gote/fu.png
28
- - images/gote/gin.png
29
- - images/gote/gyoku.png
30
- - images/gote/hisha.png
31
- - images/gote/kaku.png
32
- - images/gote/keima.png
33
- - images/gote/kin.png
34
- - images/gote/kyosha.png
35
- - images/gote/narigin.png
36
- - images/gote/narikei.png
37
- - images/gote/narikyo.png
38
- - images/gote/nonepiece.png
39
- - images/gote/ohsho.png
40
- - images/gote/ryu.png
41
- - images/gote/shori.png
42
- - images/gote/tokin.png
43
- - images/gote/uma.png
44
- - images/sente/fu.png
45
- - images/sente/gin.png
46
- - images/sente/gyoku.png
47
- - images/sente/hisha.png
48
- - images/sente/kaku.png
49
- - images/sente/keima.png
50
- - images/sente/kin.png
51
- - images/sente/kyosha.png
52
- - images/sente/narigin.png
53
- - images/sente/narikei.png
54
- - images/sente/narikyo.png
55
- - images/sente/nonepiece.png
56
- - images/sente/ohsho.png
57
- - images/sente/ryu.png
58
- - images/sente/shori.png
59
- - images/sente/tokin.png
60
- - images/sente/uma.png
27
+ - images/active/gote/fu.png
28
+ - images/active/gote/gin.png
29
+ - images/active/gote/gyoku.png
30
+ - images/active/gote/hisha.png
31
+ - images/active/gote/kaku.png
32
+ - images/active/gote/keima.png
33
+ - images/active/gote/kin.png
34
+ - images/active/gote/kyosha.png
35
+ - images/active/gote/narigin.png
36
+ - images/active/gote/narikei.png
37
+ - images/active/gote/narikyo.png
38
+ - images/active/gote/ohsho.png
39
+ - images/active/gote/ryu.png
40
+ - images/active/gote/tokin.png
41
+ - images/active/gote/uma.png
42
+ - images/active/nonepiece.png
43
+ - images/active/sente/fu.png
44
+ - images/active/sente/gin.png
45
+ - images/active/sente/gyoku.png
46
+ - images/active/sente/hisha.png
47
+ - images/active/sente/kaku.png
48
+ - images/active/sente/keima.png
49
+ - images/active/sente/kin.png
50
+ - images/active/sente/kyosha.png
51
+ - images/active/sente/narigin.png
52
+ - images/active/sente/narikei.png
53
+ - images/active/sente/narikyo.png
54
+ - images/active/sente/ohsho.png
55
+ - images/active/sente/ryu.png
56
+ - images/active/sente/tokin.png
57
+ - images/active/sente/uma.png
58
+ - images/focused/gote/fu.png
59
+ - images/focused/gote/gin.png
60
+ - images/focused/gote/gyoku.png
61
+ - images/focused/gote/hisha.png
62
+ - images/focused/gote/kaku.png
63
+ - images/focused/gote/keima.png
64
+ - images/focused/gote/kin.png
65
+ - images/focused/gote/kyosha.png
66
+ - images/focused/gote/narigin.png
67
+ - images/focused/gote/narikei.png
68
+ - images/focused/gote/narikyo.png
69
+ - images/focused/gote/ohsho.png
70
+ - images/focused/gote/ryu.png
71
+ - images/focused/gote/tokin.png
72
+ - images/focused/gote/uma.png
73
+ - images/focused/nonepiece.png
74
+ - images/focused/sente/fu.png
75
+ - images/focused/sente/gin.png
76
+ - images/focused/sente/gyoku.png
77
+ - images/focused/sente/hisha.png
78
+ - images/focused/sente/kaku.png
79
+ - images/focused/sente/keima.png
80
+ - images/focused/sente/kin.png
81
+ - images/focused/sente/kyosha.png
82
+ - images/focused/sente/narigin.png
83
+ - images/focused/sente/narikei.png
84
+ - images/focused/sente/narikyo.png
85
+ - images/focused/sente/ohsho.png
86
+ - images/focused/sente/ryu.png
87
+ - images/focused/sente/tokin.png
88
+ - images/focused/sente/uma.png
89
+ - images/gote_shori.png
90
+ - images/nomal/gote/fu.png
91
+ - images/nomal/gote/gin.png
92
+ - images/nomal/gote/gyoku.png
93
+ - images/nomal/gote/hisha.png
94
+ - images/nomal/gote/kaku.png
95
+ - images/nomal/gote/keima.png
96
+ - images/nomal/gote/kin.png
97
+ - images/nomal/gote/kyosha.png
98
+ - images/nomal/gote/narigin.png
99
+ - images/nomal/gote/narikei.png
100
+ - images/nomal/gote/narikyo.png
101
+ - images/nomal/gote/ohsho.png
102
+ - images/nomal/gote/ryu.png
103
+ - images/nomal/gote/tokin.png
104
+ - images/nomal/gote/uma.png
105
+ - images/nomal/nonepiece.png
106
+ - images/nomal/sente/fu.png
107
+ - images/nomal/sente/gin.png
108
+ - images/nomal/sente/gyoku.png
109
+ - images/nomal/sente/hisha.png
110
+ - images/nomal/sente/kaku.png
111
+ - images/nomal/sente/keima.png
112
+ - images/nomal/sente/kin.png
113
+ - images/nomal/sente/kyosha.png
114
+ - images/nomal/sente/narigin.png
115
+ - images/nomal/sente/narikei.png
116
+ - images/nomal/sente/narikyo.png
117
+ - images/nomal/sente/ohsho.png
118
+ - images/nomal/sente/ryu.png
119
+ - images/nomal/sente/tokin.png
120
+ - images/nomal/sente/uma.png
121
+ - images/sente_shori.png
61
122
  - lib/console_shogi.rb
62
123
  - lib/console_shogi/board.rb
63
124
  - lib/console_shogi/game.rb
64
125
  - lib/console_shogi/komadai.rb
65
126
  - lib/console_shogi/new_board_builder.rb
66
127
  - lib/console_shogi/piece.rb
128
+ - lib/console_shogi/piece_movement_checker.rb
67
129
  - lib/console_shogi/piece_mover.rb
68
130
  - lib/console_shogi/piece_mover_on_komadai.rb
69
131
  - lib/console_shogi/player.rb
70
- - lib/console_shogi/terminal_operator.rb
132
+ - lib/console_shogi/teban.rb
133
+ - lib/console_shogi/terminal/cursor.rb
134
+ - lib/console_shogi/terminal/display_area.rb
135
+ - lib/console_shogi/terminal/operator.rb
71
136
  - lib/console_shogi/version.rb
72
137
  homepage: https://github.com/pekepek/console-shogi
73
138
  licenses:
Binary file
@@ -1,211 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'base64'
4
- require 'tty-prompt'
5
-
6
- module ConsoleShogi
7
- class TerminalOperator
8
- class << self
9
- CursorPosition = Struct.new(:x, :y)
10
-
11
- HORIZONTAL_DISTANCE = 2
12
-
13
- KOMADAI_START_X = 21
14
- KOMADAI_GOTE_START_Y = 1
15
- KOMADAI_SENTE_START_Y = 7
16
-
17
- module EscapeSequence
18
- RESET = "\e[0m"
19
- RESET_CURSOR = "\e[1;1H"
20
- BACKGROUND_COLOR_YELLOW = "\e[43m"
21
- BACKGROUND_COLOR_GREEN = "\e[42m"
22
- TEXT_COLOR_SENTE = "\e[37m"
23
- TEXT_COLOR_GOTE = "\e[30m"
24
- end
25
-
26
- module Location
27
- NONE = :none
28
- BOARD = :board
29
- SENTE_KOMADAI = :sente_komadai
30
- GOTE_KOMADAI = :gote_komadai
31
- end
32
-
33
- def cursor_position
34
- @cursor_position ||= CursorPosition.new(x: 1, y: 1)
35
- end
36
-
37
- def image_height
38
- @image_height ||= calculate_fit_image_height
39
- end
40
-
41
- def print_board(board:, sente_komadai:, gote_komadai:)
42
- # NOTE 画面をクリア
43
- print "\e[2J"
44
-
45
- # NOTE カーソルを1行1列に移動
46
- print EscapeSequence::RESET_CURSOR
47
-
48
- board.matrix.row_vectors.each_with_index do |vector, i|
49
- vector.each_with_index do |piece, j|
50
- print_image(image: piece.image, height: image_height)
51
- end
52
-
53
- print "#{EscapeSequence::RESET}\n"
54
- end
55
-
56
- # NOTE 駒台を表示
57
- print_komadai(sente_komadai, KOMADAI_SENTE_START_Y, EscapeSequence::TEXT_COLOR_SENTE)
58
- print_komadai(gote_komadai, KOMADAI_GOTE_START_Y, EscapeSequence::TEXT_COLOR_GOTE)
59
-
60
- # NOTE back a cursor
61
- back_to_cursor
62
- end
63
-
64
- def active_piece(board:, piece_index:)
65
- back_to_cursor
66
-
67
- board.fetch_piece(x: piece_index[:x], y: piece_index[:y])
68
- end
69
-
70
- def move_cursor(key)
71
- return unless %w(A B C D).include?(key)
72
-
73
- direction =
74
- case key
75
- when 'A', 'B'
76
- key
77
- when 'C', 'D'
78
- "#{HORIZONTAL_DISTANCE}#{key}"
79
- end
80
-
81
- print "\e[#{direction}"
82
-
83
- reload_cursor_position_in_stdin!
84
- end
85
-
86
- # TODO 駒台の大きさが変わるのをどうするか考える、メソッド名考える
87
- def squares_index
88
- case cursor_position
89
- in x: 1..18, y: 1..9
90
- {x: (cursor_position.x - 1) / HORIZONTAL_DISTANCE, y: cursor_position.y - 1, location: Location::BOARD}
91
- in x: 21..38, y: 1..3
92
- {x: (cursor_position.x - 21) / HORIZONTAL_DISTANCE, y: cursor_position.y - 1, location: Location::GOTE_KOMADAI}
93
- in x: 21..38, y: 7..9
94
- {x: (cursor_position.x - 21) / HORIZONTAL_DISTANCE, y: cursor_position.y - 7, location: Location::SENTE_KOMADAI}
95
- else
96
- {x: (cursor_position.x - 1) / HORIZONTAL_DISTANCE, y: cursor_position.y - 1, location: Location::NONE}
97
- end
98
- end
99
-
100
- def select_promotion
101
- print "\e[10;1H"
102
-
103
- prompt = TTY::Prompt.new
104
-
105
- prompt.select('成りますか?', show_help: :never) {|menu|
106
- menu.choice '成る', true
107
- menu.choice '成らない', false
108
- }
109
- end
110
-
111
- def print_winner(teban)
112
- print "\e[4;7H"
113
-
114
- print_image(image: File.read("images/#{teban}/shori.png"), height: image_height * 3)
115
-
116
- print "\e[10;1H"
117
- end
118
-
119
- private
120
-
121
- IMAGE_HEIGHT_PIXEL = 240
122
-
123
- # TODO 無理やりなので、実現方法を再考する
124
- def calculate_fit_image_height
125
- start_position = fetch_cursor_position_in_stdin
126
- # NOTE NonePiece を選んでいることに意味はない
127
- print_image(image: NonePiece.new.image)
128
- end_position = fetch_cursor_position_in_stdin
129
-
130
- fixed_height = IMAGE_HEIGHT_PIXEL / (end_position[1].to_i - start_position[1].to_i)
131
-
132
- print "\e[2J"
133
- # NOTE カーソルを1行1列に移動
134
- print EscapeSequence::RESET_CURSOR
135
-
136
- fixed_height
137
- end
138
-
139
- # TODO view 用の Player 作って整理する
140
- def print_komadai(komadai, start_y, text_color)
141
- komadai.pieces.row_vectors.each_with_index do |row_pieces, i|
142
- print "\e[#{start_y + i};#{KOMADAI_START_X}H"
143
- print EscapeSequence::BACKGROUND_COLOR_YELLOW
144
- print text_color
145
-
146
- row_pieces.each do |p|
147
- print_image(image: p.image, height: image_height)
148
- end
149
-
150
- print EscapeSequence::RESET
151
- end
152
- end
153
-
154
- def fetch_cursor_position_in_stdin
155
- stdout = ''
156
-
157
- $stdin.raw do |stdin|
158
- $stdout << "\e[6n"
159
- $stdout.flush
160
-
161
- while (c = stdin.getc) != 'R'
162
- stdout += c
163
- end
164
- end
165
-
166
- stdout.match /(\d+);(\d+)/
167
- end
168
-
169
- def reload_cursor_position_in_stdin!
170
- positions = fetch_cursor_position_in_stdin
171
-
172
- @cursor_position = CursorPosition.new(x: positions[2].to_i, y: positions[1].to_i)
173
- end
174
-
175
- def back_to_cursor
176
- print "\e[#{cursor_position.y};#{cursor_position.x}H"
177
- end
178
-
179
- # TODO 画像を表示するためのメソッド、場所検討
180
- def print_image(image:, width: nil, height: nil)
181
- encoded_image = Base64.strict_encode64(image)
182
-
183
- print_osc
184
- print "1337;File=inline=1"
185
- print ";size=#{image.size}"
186
- print ";name=#{encoded_image}"
187
- print ";width=#{width}px" unless width.nil?
188
- print ";height=#{height}px" unless height.nil?
189
- print ":#{encoded_image}"
190
- print_st
191
- end
192
-
193
- def print_osc
194
- # NOTE \e] で始まるシーケンスは全てのターミナルで扱えるわけでは無い
195
- if ENV['TERM'].start_with?('screen') || ENV['TERM'].start_with?('tmux')
196
- print "\ePtmux;\e\e]"
197
- else
198
- print "\e]"
199
- end
200
- end
201
-
202
- def print_st
203
- if ENV['TERM'].start_with?('screen') || ENV['TERM'].start_with?('tmux')
204
- print "\a\e\\"
205
- else
206
- print "\a"
207
- end
208
- end
209
- end
210
- end
211
- end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes