console-shogi 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +21 -0
- data/images/active/gote/fu.png +0 -0
- data/images/active/gote/gin.png +0 -0
- data/images/active/gote/gyoku.png +0 -0
- data/images/active/gote/hisha.png +0 -0
- data/images/active/gote/kaku.png +0 -0
- data/images/active/gote/keima.png +0 -0
- data/images/active/gote/kin.png +0 -0
- data/images/active/gote/kyosha.png +0 -0
- data/images/active/gote/narigin.png +0 -0
- data/images/active/gote/narikei.png +0 -0
- data/images/active/gote/narikyo.png +0 -0
- data/images/active/gote/ohsho.png +0 -0
- data/images/active/gote/ryu.png +0 -0
- data/images/active/gote/tokin.png +0 -0
- data/images/active/gote/uma.png +0 -0
- data/images/active/nonepiece.png +0 -0
- data/images/active/sente/fu.png +0 -0
- data/images/active/sente/gin.png +0 -0
- data/images/active/sente/gyoku.png +0 -0
- data/images/active/sente/hisha.png +0 -0
- data/images/active/sente/kaku.png +0 -0
- data/images/active/sente/keima.png +0 -0
- data/images/active/sente/kin.png +0 -0
- data/images/active/sente/kyosha.png +0 -0
- data/images/active/sente/narigin.png +0 -0
- data/images/active/sente/narikei.png +0 -0
- data/images/active/sente/narikyo.png +0 -0
- data/images/active/sente/ohsho.png +0 -0
- data/images/active/sente/ryu.png +0 -0
- data/images/active/sente/tokin.png +0 -0
- data/images/active/sente/uma.png +0 -0
- data/images/focused/gote/fu.png +0 -0
- data/images/focused/gote/gin.png +0 -0
- data/images/focused/gote/gyoku.png +0 -0
- data/images/focused/gote/hisha.png +0 -0
- data/images/focused/gote/kaku.png +0 -0
- data/images/focused/gote/keima.png +0 -0
- data/images/focused/gote/kin.png +0 -0
- data/images/focused/gote/kyosha.png +0 -0
- data/images/focused/gote/narigin.png +0 -0
- data/images/focused/gote/narikei.png +0 -0
- data/images/focused/gote/narikyo.png +0 -0
- data/images/focused/gote/ohsho.png +0 -0
- data/images/focused/gote/ryu.png +0 -0
- data/images/focused/gote/tokin.png +0 -0
- data/images/focused/gote/uma.png +0 -0
- data/images/focused/nonepiece.png +0 -0
- data/images/focused/sente/fu.png +0 -0
- data/images/focused/sente/gin.png +0 -0
- data/images/focused/sente/gyoku.png +0 -0
- data/images/focused/sente/hisha.png +0 -0
- data/images/focused/sente/kaku.png +0 -0
- data/images/focused/sente/keima.png +0 -0
- data/images/focused/sente/kin.png +0 -0
- data/images/focused/sente/kyosha.png +0 -0
- data/images/focused/sente/narigin.png +0 -0
- data/images/focused/sente/narikei.png +0 -0
- data/images/focused/sente/narikyo.png +0 -0
- data/images/focused/sente/ohsho.png +0 -0
- data/images/focused/sente/ryu.png +0 -0
- data/images/focused/sente/tokin.png +0 -0
- data/images/focused/sente/uma.png +0 -0
- data/images/history_button/left.png +0 -0
- data/images/history_button/play.png +0 -0
- data/images/history_button/right.png +0 -0
- data/lib/console_shogi/board.rb +5 -9
- data/lib/console_shogi/game.rb +98 -24
- data/lib/console_shogi/game_history.rb +60 -0
- data/lib/console_shogi/grid_position.rb +6 -0
- data/lib/console_shogi/komadai.rb +22 -18
- data/lib/console_shogi/new_board_builder.rb +41 -41
- data/lib/console_shogi/piece.rb +39 -23
- data/lib/console_shogi/piece_movement_checker.rb +46 -0
- data/lib/console_shogi/piece_mover.rb +21 -68
- data/lib/console_shogi/piece_mover_from_board.rb +57 -0
- data/lib/console_shogi/piece_mover_from_komadai.rb +51 -0
- data/lib/console_shogi/player.rb +5 -13
- data/lib/console_shogi/teban.rb +8 -0
- data/lib/console_shogi/terminal/cursor.rb +74 -0
- data/lib/console_shogi/terminal/display_area.rb +122 -0
- data/lib/console_shogi/terminal/operator.rb +249 -0
- data/lib/console_shogi/version.rb +1 -1
- data/lib/console_shogi.rb +11 -3
- metadata +110 -39
- data/images/gote/nonepiece.png +0 -0
- data/lib/console_shogi/piece_mover_on_komadai.rb +0 -65
- data/lib/console_shogi/terminal_operator.rb +0 -211
- /data/images/{gote/shori.png → gote_shori.png} +0 -0
- /data/images/{gote → nomal/gote}/fu.png +0 -0
- /data/images/{gote → nomal/gote}/gin.png +0 -0
- /data/images/{gote → nomal/gote}/gyoku.png +0 -0
- /data/images/{gote → nomal/gote}/hisha.png +0 -0
- /data/images/{gote → nomal/gote}/kaku.png +0 -0
- /data/images/{gote → nomal/gote}/keima.png +0 -0
- /data/images/{gote → nomal/gote}/kin.png +0 -0
- /data/images/{gote → nomal/gote}/kyosha.png +0 -0
- /data/images/{gote → nomal/gote}/narigin.png +0 -0
- /data/images/{gote → nomal/gote}/narikei.png +0 -0
- /data/images/{gote → nomal/gote}/narikyo.png +0 -0
- /data/images/{gote → nomal/gote}/ohsho.png +0 -0
- /data/images/{gote → nomal/gote}/ryu.png +0 -0
- /data/images/{gote → nomal/gote}/tokin.png +0 -0
- /data/images/{gote → nomal/gote}/uma.png +0 -0
- /data/images/{sente → nomal}/nonepiece.png +0 -0
- /data/images/{sente → nomal/sente}/fu.png +0 -0
- /data/images/{sente → nomal/sente}/gin.png +0 -0
- /data/images/{sente → nomal/sente}/gyoku.png +0 -0
- /data/images/{sente → nomal/sente}/hisha.png +0 -0
- /data/images/{sente → nomal/sente}/kaku.png +0 -0
- /data/images/{sente → nomal/sente}/keima.png +0 -0
- /data/images/{sente → nomal/sente}/kin.png +0 -0
- /data/images/{sente → nomal/sente}/kyosha.png +0 -0
- /data/images/{sente → nomal/sente}/narigin.png +0 -0
- /data/images/{sente → nomal/sente}/narikei.png +0 -0
- /data/images/{sente → nomal/sente}/narikyo.png +0 -0
- /data/images/{sente → nomal/sente}/ohsho.png +0 -0
- /data/images/{sente → nomal/sente}/ryu.png +0 -0
- /data/images/{sente → nomal/sente}/tokin.png +0 -0
- /data/images/{sente → nomal/sente}/uma.png +0 -0
- /data/images/{sente/shori.png → sente_shori.png} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bee75f732b33e177d7b2c15939508663a391bc2d593692273a1a1f47ae654543
|
4
|
+
data.tar.gz: d78846e34e4afbeea51dfd4558e9c076aee6625c6ad43129fb01cff9c36d41a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b0aeed55b0fcaedbe879703c3d7e20fc38a6fa5e2a0617d627ff6f873766aff6f4963dc117f032b64911021a46888ebb2229ed6d4a4231bd91d9ecbcf5a868a
|
7
|
+
data.tar.gz: 926eeda23c9e565c45ec8290c0ecf5ca607adfaea24c29f1a95c858f952af948b7e371ae8408f32512c3acd720bb3af5873dce62aa8ff435e0801d1cf2b1cc35
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1 +1,22 @@
|
|
1
1
|
# console-shogi
|
2
|
+
|
3
|
+
You can play the Shogi in your terminal ☗☖
|
4
|
+
|
5
|
+
Maybe, you’ll hard to see if you don’t increase the font size of the terminal.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install console-shogi
|
11
|
+
```
|
12
|
+
|
13
|
+
## Start Game
|
14
|
+
|
15
|
+
```
|
16
|
+
console-shogi
|
17
|
+
```
|
18
|
+
|
19
|
+
## Commands
|
20
|
+
|
21
|
+
* move a cursor : `direction keys` ←↓↑→
|
22
|
+
* select and drop a piece : `Enter`
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/console_shogi/board.rb
CHANGED
@@ -12,6 +12,10 @@ module ConsoleShogi
|
|
12
12
|
@pieces
|
13
13
|
end
|
14
14
|
|
15
|
+
def deep_copy
|
16
|
+
Board.new(pieces: pieces.map(&:dup).to_a)
|
17
|
+
end
|
18
|
+
|
15
19
|
def within_range?(x:, y:)
|
16
20
|
case {x: x, y: y}
|
17
21
|
in x: 0..8, y: 0..8
|
@@ -34,16 +38,8 @@ module ConsoleShogi
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def move_piece!(from:, to:)
|
37
|
-
|
41
|
+
@pieces[to[:y], to[:x]] = @pieces[from[:y], from[:x]]
|
38
42
|
@pieces[from[:y], from[:x]] = NonePiece.new
|
39
|
-
|
40
|
-
to_piece = @pieces[to[:y], to[:x]]
|
41
|
-
|
42
|
-
# NOTE 駒を取る、リファクタする
|
43
|
-
# from_piece.player で player 取るの違和感
|
44
|
-
from_piece.player.capture_piece!(to_piece) unless to_piece.none?
|
45
|
-
|
46
|
-
@pieces[to[:y], to[:x]] = from_piece
|
47
43
|
end
|
48
44
|
|
49
45
|
private
|
data/lib/console_shogi/game.rb
CHANGED
@@ -5,15 +5,25 @@ require 'io/console'
|
|
5
5
|
module ConsoleShogi
|
6
6
|
class Game
|
7
7
|
def initialize
|
8
|
-
@sente_player = Player.new(teban:
|
9
|
-
@gote_player = Player.new(teban:
|
10
|
-
@board = NewBoardBuilder.build
|
8
|
+
@sente_player = Player.new(teban: Teban::SENTE)
|
9
|
+
@gote_player = Player.new(teban: Teban::GOTE)
|
10
|
+
@board = NewBoardBuilder.build
|
11
|
+
|
12
|
+
@selected_cursor = nil
|
13
|
+
@teban_player = @sente_player
|
14
|
+
|
15
|
+
@game_histories = [{board: board.deep_copy, sente_komadai: sente_player.komadai.deep_copy, gote_komadai: gote_player.komadai.deep_copy}]
|
16
|
+
|
17
|
+
Terminal::Operator.clear_scrren
|
18
|
+
Terminal::Operator.print_board(board: board, sente_komadai: sente_player.komadai, gote_komadai: gote_player.komadai)
|
19
|
+
Terminal::Operator.print_history_button
|
20
|
+
Terminal::Operator.print_teban(teban_player.teban)
|
11
21
|
end
|
12
22
|
|
13
23
|
def start
|
14
|
-
TerminalOperator.print_board(board: board, sente_komadai: sente_player.komadai, gote_komadai: gote_player.komadai)
|
15
|
-
|
16
24
|
while key = STDIN.getch
|
25
|
+
cursor = Terminal::Operator.cursor
|
26
|
+
|
17
27
|
# NOTE Ctrl-C を押したら終了
|
18
28
|
if key == "\C-c"
|
19
29
|
exit
|
@@ -21,30 +31,54 @@ module ConsoleShogi
|
|
21
31
|
elsif key == "\e" && STDIN.getch == "["
|
22
32
|
key = STDIN.getch
|
23
33
|
|
24
|
-
|
34
|
+
@last_cursor_on_grid = cursor.dup unless cursor.grid_position.location.outside?
|
35
|
+
|
36
|
+
cursor.move(key)
|
37
|
+
|
38
|
+
# TODO 選択したピースは色を変えないようにしている。状態の持ち方を見直したい
|
39
|
+
deactive_piece(last_cursor_on_grid) if selected_cursor&.grid_position != last_cursor_on_grid.grid_position
|
40
|
+
focus_piece(cursor) if selected_cursor&.grid_position != cursor.grid_position
|
25
41
|
# NOTE Enter を押したら駒を移動
|
26
42
|
elsif key == "\r"
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
when :board
|
32
|
-
PieceMover.new(board: board, from: index).move!
|
33
|
-
when :sente_komadai
|
34
|
-
PieceMoverOnKomadai.new(board: board, komadai: sente_player.komadai, from: index).drop!
|
35
|
-
when :gote_komadai
|
36
|
-
PieceMoverOnKomadai.new(board: board, komadai: gote_player.komadai, from: index).drop!
|
43
|
+
if cursor.grid_position.location.history?
|
44
|
+
GameHistory.new(game_histories: game_histories).start
|
45
|
+
|
46
|
+
next
|
37
47
|
end
|
38
48
|
|
39
|
-
|
40
|
-
|
49
|
+
if selected_cursor.nil?
|
50
|
+
# TODO PieceMover の can_move? と分散してしまっている気もする
|
51
|
+
next if cursor.grid_position.location.outside?
|
52
|
+
|
53
|
+
active_piece(cursor)
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
next unless
|
55
|
+
@selected_cursor = cursor.dup
|
56
|
+
else
|
57
|
+
next unless cursor.grid_position.location.board?
|
45
58
|
|
46
|
-
|
47
|
-
|
59
|
+
piece_mover = PieceMover.build(board: board, player: teban_player, from_cursor: selected_cursor, to_cursor: cursor)
|
60
|
+
|
61
|
+
piece_mover.move!
|
62
|
+
|
63
|
+
if piece_mover.moved_piece?
|
64
|
+
Terminal::Operator.print_diff_board(previous_board: game_histories.last[:board], board: board, sente_komadai: sente_player.komadai, gote_komadai: gote_player.komadai)
|
65
|
+
|
66
|
+
@game_histories << {board: board.deep_copy, sente_komadai: sente_player.komadai.deep_copy, gote_komadai: gote_player.komadai.deep_copy}
|
67
|
+
|
68
|
+
if teban_player.win?
|
69
|
+
Terminal::Operator.print_winner(teban_player)
|
70
|
+
|
71
|
+
exit
|
72
|
+
else
|
73
|
+
change_teban!
|
74
|
+
|
75
|
+
Terminal::Operator.print_teban(teban_player.teban)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
deactive_piece(selected_cursor)
|
79
|
+
end
|
80
|
+
|
81
|
+
@selected_cursor = nil
|
48
82
|
end
|
49
83
|
end
|
50
84
|
end
|
@@ -52,6 +86,46 @@ module ConsoleShogi
|
|
52
86
|
|
53
87
|
private
|
54
88
|
|
55
|
-
attr_reader :board, :sente_player, :gote_player
|
89
|
+
attr_reader :board, :sente_player, :gote_player, :selected_cursor, :teban_player, :game_histories, :last_cursor_on_grid
|
90
|
+
|
91
|
+
def change_teban!
|
92
|
+
@teban_player = teban_player == sente_player ? gote_player : sente_player
|
93
|
+
end
|
94
|
+
|
95
|
+
# TODO ここらへんイケてないのでリファクタしたい
|
96
|
+
def active_piece(cursor)
|
97
|
+
location = fetch_piece_location_object(cursor.grid_position.location)
|
98
|
+
|
99
|
+
return if location.nil?
|
100
|
+
|
101
|
+
Terminal::Operator.active_piece(board: location, cursor: cursor)
|
102
|
+
end
|
103
|
+
|
104
|
+
def deactive_piece(cursor)
|
105
|
+
location = fetch_piece_location_object(cursor.grid_position.location)
|
106
|
+
|
107
|
+
return if location.nil?
|
108
|
+
|
109
|
+
Terminal::Operator.deactive_piece(board: location, previous_cursor: cursor)
|
110
|
+
end
|
111
|
+
|
112
|
+
def focus_piece(cursor)
|
113
|
+
location = fetch_piece_location_object(cursor.grid_position.location)
|
114
|
+
|
115
|
+
return if location.nil?
|
116
|
+
|
117
|
+
Terminal::Operator.focus_piece(board: location, cursor: cursor)
|
118
|
+
end
|
119
|
+
|
120
|
+
def fetch_piece_location_object(cursor_location)
|
121
|
+
case cursor_location.name
|
122
|
+
when :board
|
123
|
+
board
|
124
|
+
when :sente_komadai
|
125
|
+
sente_player.komadai
|
126
|
+
when :gote_komadai
|
127
|
+
gote_player.komadai
|
128
|
+
end
|
129
|
+
end
|
56
130
|
end
|
57
131
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
|
5
|
+
module ConsoleShogi
|
6
|
+
class GameHistory
|
7
|
+
def initialize(game_histories:)
|
8
|
+
@game_histories = game_histories
|
9
|
+
# TODO game_count という名前は分かりづらいので変える
|
10
|
+
@game_count = game_histories.count
|
11
|
+
|
12
|
+
Terminal::Operator.print_start_history
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
while key = STDIN.getch
|
17
|
+
cursor = Terminal::Operator.cursor
|
18
|
+
|
19
|
+
# NOTE Ctrl-C を押したら終了
|
20
|
+
if key == "\C-c"
|
21
|
+
exit
|
22
|
+
# NOTE 矢印キーを押したらカーソルを移動
|
23
|
+
elsif key == "\e" && STDIN.getch == "["
|
24
|
+
key = STDIN.getch
|
25
|
+
|
26
|
+
cursor.move(key)
|
27
|
+
elsif key == "\r"
|
28
|
+
location = cursor.grid_position.location
|
29
|
+
|
30
|
+
next unless location.history?
|
31
|
+
|
32
|
+
if location.resume?
|
33
|
+
Terminal::Operator.clear_scrren
|
34
|
+
|
35
|
+
Terminal::Operator.print_board(board: game_histories.last[:board], sente_komadai: game_histories.last[:sente_komadai], gote_komadai: game_histories.last[:gote_komadai])
|
36
|
+
Terminal::Operator.print_history_button
|
37
|
+
|
38
|
+
return
|
39
|
+
elsif location.back?
|
40
|
+
next if game_count == 1
|
41
|
+
|
42
|
+
@game_count -= 1
|
43
|
+
|
44
|
+
Terminal::Operator.print_board(board: game_histories[game_count - 1][:board], sente_komadai: game_histories[game_count - 1][:sente_komadai], gote_komadai: game_histories[game_count - 1][:gote_komadai])
|
45
|
+
elsif location.forward?
|
46
|
+
next if game_count == game_histories.count
|
47
|
+
|
48
|
+
@game_count += 1
|
49
|
+
|
50
|
+
Terminal::Operator.print_board(board: game_histories[game_count - 1][:board], sente_komadai: game_histories[game_count - 1][:sente_komadai], gote_komadai: game_histories[game_count - 1][:gote_komadai])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :game_histories, :game_count
|
59
|
+
end
|
60
|
+
end
|
@@ -8,16 +8,12 @@ module ConsoleShogi
|
|
8
8
|
|
9
9
|
attr_reader :pieces
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@pieces =
|
11
|
+
def initialize(pieces: empty_pieces)
|
12
|
+
@pieces = Matrix.rows(pieces)
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def have_space?
|
20
|
-
pieces.any?(&:none?)
|
15
|
+
def deep_copy
|
16
|
+
Komadai.new(pieces: pieces.map(&:dup).to_a)
|
21
17
|
end
|
22
18
|
|
23
19
|
def fetch_piece(x:, y:)
|
@@ -25,35 +21,43 @@ module ConsoleShogi
|
|
25
21
|
end
|
26
22
|
|
27
23
|
def put(piece:)
|
24
|
+
expand! unless have_space?
|
25
|
+
|
28
26
|
index = pieces.index(&:none?)
|
29
27
|
|
30
|
-
|
28
|
+
piece = piece.original if piece.promoted?
|
31
29
|
|
32
30
|
@pieces[*index] = piece
|
33
31
|
|
34
32
|
@pieces = sort_pieces
|
35
33
|
end
|
36
34
|
|
37
|
-
def pick_up_piece!(
|
38
|
-
@pieces[
|
35
|
+
def pick_up_piece!(x:, y:)
|
36
|
+
@pieces[y, x] = NonePiece.new
|
39
37
|
@pieces = sort_pieces
|
40
38
|
end
|
41
39
|
|
42
40
|
private
|
43
41
|
|
42
|
+
def expand!
|
43
|
+
@pieces = pieces.hstack(empty_pieces)
|
44
|
+
end
|
45
|
+
|
46
|
+
def have_space?
|
47
|
+
pieces.any?(&:none?)
|
48
|
+
end
|
49
|
+
|
44
50
|
def sort_pieces
|
45
51
|
column_num = pieces.count / 3
|
46
52
|
Matrix.rows(pieces.sort_by {|p| -p.number }.each_slice(column_num).to_a)
|
47
53
|
end
|
48
54
|
|
49
55
|
def empty_pieces
|
50
|
-
|
51
|
-
[
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
]
|
56
|
-
)
|
56
|
+
[
|
57
|
+
[NonePiece.new, NonePiece.new, NonePiece.new],
|
58
|
+
[NonePiece.new, NonePiece.new, NonePiece.new],
|
59
|
+
[NonePiece.new, NonePiece.new, NonePiece.new]
|
60
|
+
]
|
57
61
|
end
|
58
62
|
end
|
59
63
|
end
|