reachy 1.1

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.
@@ -0,0 +1,242 @@
1
+ require_relative 'scoring'
2
+
3
+ ##############################################
4
+ # Round record class
5
+ ##############################################
6
+ module Reachy
7
+ class Round
8
+
9
+ attr_reader :name # Name of round (e.g. E1B2R1)
10
+ attr_reader :mode # Game mode
11
+ attr_reader :wind # Round wind
12
+ attr_reader :number # Round number
13
+ attr_reader :bonus # Current bonus sticks
14
+ attr_accessor :riichi # Current riichi sticks
15
+ attr_accessor :scores # Hash of <player's name> => <score>
16
+
17
+ # Initialize round
18
+ # Param: round - hash of round data
19
+ # Populate Round object with info from hash
20
+ def initialize(db)
21
+ @name = db["name"]
22
+ @wind = db["wind"]
23
+ @number = db["number"]
24
+ @bonus = db["bonus"]
25
+ @riichi = db["riichi"]
26
+ @scores = db["scores"]
27
+ @mode = @scores.length
28
+ end
29
+
30
+ # Return a deep copy of this Round object
31
+ def clone
32
+ return Marshal.load(Marshal.dump(self))
33
+ end
34
+
35
+ # Return Hash object representing Round object
36
+ def to_h
37
+ hash = {}
38
+ self.instance_variables.each do |var|
39
+ hash[var.to_s[1..-1]] = self.instance_variable_get(var)
40
+ end
41
+ hash.delete("mode")
42
+ return hash
43
+ end
44
+
45
+ # Add riichi stick declared by player
46
+ # Param: player - string of player's name
47
+ # Return: true if successful, else false
48
+ # Note: - round name should not be changed
49
+ # - do not write to file here
50
+ def add_riichi(player)
51
+ if @scores[player] >= Scoring::P_RIICHI
52
+ @riichi += 1
53
+ @scores[player] -= Scoring::P_RIICHI
54
+ return true
55
+ else
56
+ puts "Unable to declare riichi: not enough points"
57
+ return false
58
+ end
59
+ end
60
+
61
+ # Update wind and round number to next round
62
+ def next_round
63
+ if not @wind
64
+ @wind = "E"
65
+ @number = 1
66
+ elsif @number == @mode
67
+ if @wind == "W"
68
+ printf "Already in last possible round (West %d)!\n", @number
69
+ return []
70
+ else
71
+ @wind = (@wind == "E" ? "S" : "W")
72
+ @number = 1
73
+ end
74
+ else
75
+ @number += 1
76
+ end
77
+ end
78
+
79
+ # Give bonus and riichi points to player
80
+ # Param: winner - string of player's name to award points to
81
+ # loser - list of players who pay for bonus points
82
+ # dealer - bool indicating whether winner was dealer
83
+ # Return: true if successful, else false
84
+ def award_bonus(winner,loser,dealer)
85
+ if @scores.include?(winner)
86
+ @scores[winner] += @bonus*Scoring::P_BONUS
87
+ share_count = loser.length
88
+ if share_count>1 then share_count += (@mode==3 ? 1 : 0) end
89
+ bonus_paym = (@bonus*Scoring::P_BONUS)/share_count
90
+ loser.each do |l|
91
+ if @scores.include?(l)
92
+ @scores[l] -= bonus_paym
93
+ else
94
+ printf "Error: \"%s\" not in current list of players\n", l
95
+ end
96
+ end
97
+ @bonus = 0 if not dealer
98
+ @scores[winner] += @riichi*Scoring::P_RIICHI
99
+ @riichi = 0
100
+ return true
101
+ else
102
+ printf "Error: \"%s\" not in current list of players\n", winner
103
+ return false
104
+ end
105
+ end
106
+
107
+ # Update round name
108
+ def update_name
109
+ @name = @wind ? (@wind + @number.to_s) : ""
110
+ @name += "B" + @bonus.to_s if @bonus > 0
111
+ @name += "R" + @riichi.to_s if @riichi > 0
112
+ end
113
+
114
+ # Update round data from given input
115
+ # Param: type - round result type (tsumo/ron/tenpai/noten/chombo)
116
+ # dealer - string of dealer's name
117
+ # winner - list of winner's name or players in tenpai
118
+ # loser - list of players who chombo or did not win
119
+ # hand - list of list of hand values (e.g. [["mangan"], [2,60]])
120
+ # Return: true if successful, else false
121
+ # Usage: This round is a clone of previous round, so just update its values.
122
+ # Multiple ron winners: - winner and hand lists must match
123
+ # - first winner in list gets bonus/riichi points
124
+ def update_round(type,dealer,winner,loser,hand)
125
+ # Verify inputs
126
+ if (dealer == nil)
127
+ puts "Error: Missing dealer's name"
128
+ return false
129
+ end
130
+ if (hand.empty? || hand.first.empty?) && (type==T_TSUMO || type==T_RON)
131
+ puts "Error: Missing hand value"
132
+ return false
133
+ end
134
+
135
+ dealer_flag = winner.include?(dealer)
136
+
137
+ # Handle each round type
138
+ case type
139
+
140
+ when T_TSUMO
141
+ # Tsumo type: loser = everyone else
142
+ losers = @scores.keys
143
+ losers -= winner
144
+ return false if not self.award_bonus(winner.first,losers,dealer_flag)
145
+ if dealer_flag then @bonus += 1 else self.next_round end
146
+ score_h = Scoring.get_tsumo(dealer_flag, hand.first)
147
+ winner.each do |w|
148
+ @scores[w] += if dealer_flag then score_h["nondealer"]*(@mode-1)
149
+ else (score_h["dealer"]+score_h["nondealer"]*(@mode-2)) end
150
+ end
151
+ losers.each do |l|
152
+ @scores[l] -= score_h[l==dealer ? "dealer" : "nondealer"]
153
+ end
154
+
155
+ when T_RON
156
+ # Ron type - can have multiple winners off of same loser
157
+ return false if not self.award_bonus(winner.first,loser,dealer_flag)
158
+ if dealer_flag then @bonus += 1 else self.next_round end
159
+ winner.zip(hand).each do |w,h|
160
+ paym = Scoring.get_ron((w==dealer),h)
161
+ @scores[w] += paym
162
+ @scores[loser.first] -= paym
163
+ end
164
+
165
+ when T_TENPAI
166
+ # Tenpai type: losers = all - winners
167
+ losers = @scores.keys
168
+ losers -= winner
169
+ if winner.length < @mode
170
+ if dealer_flag then @bonus += 1 else self.next_round end
171
+ total = @mode==4 ? Scoring::P_TENPAI_4 : Scoring::P_TENPAI_3
172
+ paym = total / losers.length
173
+ recv = total / winner.length
174
+ winner.each do |w|
175
+ @scores[w] += recv
176
+ end
177
+ losers.each do |l|
178
+ @scores[l] -= paym
179
+ end
180
+ end
181
+
182
+ when T_NOTEN
183
+ # Noten type: ignore all other params
184
+ self.next_round
185
+
186
+ when T_CHOMBO
187
+ # Chombo type: loser = chombo player, winner = everyone else
188
+ winners = @scores.keys
189
+ winners -= loser
190
+ dealer_flag = loser.include?(dealer)
191
+ score_h = Scoring.get_chombo(dealer_flag)
192
+ @scores[loser.first] -= if dealer_flag then score_h["nondealer"]*(@mode-1)
193
+ else (score_h["dealer"] + score_h["nondealer"]*(@mode-2)) end
194
+ winners.each do |w|
195
+ @scores[w] += score_h[w==dealer ? "dealer" : "nondealer"]
196
+ end
197
+
198
+ else
199
+ printf "Invalid round result type\n", type
200
+ puts nil
201
+ return false
202
+ end
203
+
204
+ return true
205
+ end
206
+
207
+ # Print single line round scores
208
+ # Param: delta - hash of score deltas between this round and previous one
209
+ # ongoing - bool indicating if round is ongoing (optional)
210
+ def print_scores(delta,ongoing=false)
211
+ round_name = @name
212
+ round_name += "*" if ongoing
213
+ printf "%-#{COL_SPACING}s", round_name
214
+ @scores.each do |key,val|
215
+ if delta
216
+ d = delta[key]
217
+ d = 0.0 if not d
218
+ if d == 0 # not sure why one-liner doesn't work here...
219
+ d = "="
220
+ elsif d < 0
221
+ d = d.to_s + "k"
222
+ else
223
+ d = "+" + d.to_s + "k"
224
+ end
225
+ val = val.to_s + "(" + d + ")"
226
+ else
227
+ val = val.to_s
228
+ end
229
+ printf "%-#{COL_SPACING}s", val
230
+ end
231
+ puts nil
232
+ end
233
+
234
+ # Print bonus and riichi sticks summary
235
+ def print_sticks
236
+ printf " %-#{COL_SPACING}s: %d\n", "Bonus sticks", @bonus
237
+ printf " %-#{COL_SPACING}s: %d\n", "Riichi sticks", @riichi
238
+ puts nil
239
+ end
240
+
241
+ end
242
+ end
@@ -0,0 +1,169 @@
1
+ ##############################################
2
+ # Hash objects containing scoring tables
3
+ ##############################################
4
+ module Reachy
5
+
6
+ # Hash of tsumo scores
7
+ H_TSUMO = {
8
+ "dealer" => {
9
+ "han_1" => {
10
+ "fu_20" => 400,
11
+ "fu_30" => 500,
12
+ "fu_40" => 700,
13
+ "fu_50" => 800,
14
+ "fu_60" => 1000,
15
+ "fu_70" => 1200
16
+ },
17
+ "han_2" => {
18
+ "fu_20" => 700,
19
+ "fu_30" => 1000,
20
+ "fu_40" => 1300,
21
+ "fu_50" => 1600,
22
+ "fu_60" => 2000,
23
+ "fu_70" => 2300
24
+ },
25
+ "han_3" => {
26
+ "fu_20" => 1300,
27
+ "fu_25" => 1600,
28
+ "fu_30" => 2000,
29
+ "fu_40" => 2600,
30
+ "fu_50" => 3200,
31
+ "fu_60" => 3900
32
+ },
33
+ "han_4" => {
34
+ "fu_20" => 2600,
35
+ "fu_25" => 3200,
36
+ "fu_30" => 3900
37
+ },
38
+ "mangan" => 4000,
39
+ "haneman" => 6000,
40
+ "baiman" => 8000,
41
+ "sanbaiman" => 12000,
42
+ "yakuman" => 16000,
43
+ #"double_yakuman" => 32000
44
+ },
45
+ "nondealer" => {
46
+ "han_1" => {
47
+ "fu_20" => { "dealer" => 400, "nondealer" => 200 },
48
+ "fu_30" => { "dealer" => 500, "nondealer" => 300 },
49
+ "fu_40" => { "dealer" => 700, "nondealer" => 400 },
50
+ "fu_50" => { "dealer" => 800, "nondealer" => 400 },
51
+ "fu_60" => { "dealer" => 1000, "nondealer" => 500 },
52
+ "fu_70" => { "dealer" => 1200, "nondealer" => 600 }
53
+ },
54
+ "han_2" => {
55
+ "fu_20" => { "dealer" => 700, "nondealer" => 400 },
56
+ "fu_30" => { "dealer" => 1000, "nondealer" => 500 },
57
+ "fu_40" => { "dealer" => 1300, "nondealer" => 700 },
58
+ "fu_50" => { "dealer" => 1600, "nondealer" => 800 },
59
+ "fu_60" => { "dealer" => 2000, "nondealer" => 1000 },
60
+ "fu_70" => { "dealer" => 2300, "nondealer" => 1200 }
61
+ },
62
+ "han_3" => {
63
+ "fu_20" => { "dealer" => 1300, "nondealer" => 700 },
64
+ "fu_25" => { "dealer" => 1600, "nondealer" => 800 },
65
+ "fu_30" => { "dealer" => 2000, "nondealer" => 1000 },
66
+ "fu_40" => { "dealer" => 2600, "nondealer" => 1300 },
67
+ "fu_50" => { "dealer" => 3200, "nondealer" => 1600 },
68
+ "fu_60" => { "dealer" => 3900, "nondealer" => 2000 }
69
+ },
70
+ "han_4" => {
71
+ "fu_20" => { "dealer" => 2600, "nondealer" => 1300 },
72
+ "fu_25" => { "dealer" => 3200, "nondealer" => 1600 },
73
+ "fu_30" => { "dealer" => 3900, "nondealer" => 2000 }
74
+ },
75
+ "mangan" => { "dealer" => 4000, "nondealer" => 2000 },
76
+ "haneman" => { "dealer" => 6000, "nondealer" => 3000 },
77
+ "baiman" => { "dealer" => 8000, "nondealer" => 4000 },
78
+ "sanbaiman" => { "dealer" => 12000, "nondealer" => 6000 },
79
+ "yakuman" => { "dealer" => 16000, "nondealer" => 8000 },
80
+ #"double_yakuman" => { "dealer" => 32000, "nondealer" => 16000 }
81
+ }
82
+ }
83
+
84
+ # Hash of ron scores
85
+ H_RON = {
86
+ "dealer" => {
87
+ "han_1" => {
88
+ "fu_20" => 1000,
89
+ "fu_30" => 1500,
90
+ "fu_40" => 2000,
91
+ "fu_50" => 2400,
92
+ "fu_60" => 2900,
93
+ "fu_70" => 3400
94
+ },
95
+ "han_2" => {
96
+ "fu_20" => 2000,
97
+ "fu_25" => 2400,
98
+ "fu_30" => 2900,
99
+ "fu_40" => 3900,
100
+ "fu_50" => 4800,
101
+ "fu_60" => 5800,
102
+ "fu_70" => 6800
103
+ },
104
+ "han_3" => {
105
+ "fu_20" => 3900,
106
+ "fu_25" => 4800,
107
+ "fu_30" => 5800,
108
+ "fu_40" => 7700,
109
+ "fu_50" => 9600,
110
+ "fu_60" => 11600
111
+ },
112
+ "han_4" => {
113
+ "fu_20" => 7700,
114
+ "fu_25" => 9600,
115
+ "fu_30" => 11600
116
+ },
117
+ "mangan" => 12000,
118
+ "haneman" => 18000,
119
+ "baiman" => 24000,
120
+ "sanbaiman" => 36000,
121
+ "yakuman" => 48000,
122
+ #"double_yakuman" => 96000
123
+ },
124
+ "nondealer" => {
125
+ "han_1" => {
126
+ "fu_20" => 700,
127
+ "fu_30" => 1000,
128
+ "fu_40" => 1300,
129
+ "fu_50" => 1600,
130
+ "fu_60" => 2000,
131
+ "fu_70" => 2300
132
+ },
133
+ "han_2" => {
134
+ "fu_20" => 1300,
135
+ "fu_30" => 2000,
136
+ "fu_25" => 1600,
137
+ "fu_40" => 2600,
138
+ "fu_50" => 3200,
139
+ "fu_60" => 3900,
140
+ "fu_70" => 4500
141
+ },
142
+ "han_3" => {
143
+ "fu_20" => 2600,
144
+ "fu_25" => 3200,
145
+ "fu_30" => 3900,
146
+ "fu_40" => 5200,
147
+ "fu_50" => 6300,
148
+ "fu_60" => 7700
149
+ },
150
+ "han_4" => {
151
+ "fu_20" => 5200,
152
+ "fu_25" => 6400,
153
+ "fu_30" => 7700
154
+ },
155
+ "mangan" => 8000,
156
+ "haneman" => 12000,
157
+ "baiman" => 16000,
158
+ "sanbaiman" => 24000,
159
+ "yakuman" => 32000,
160
+ #"double_yakuman" => 64000
161
+ }
162
+ }
163
+
164
+ # Hash of chombo scores
165
+ H_CHOMBO = {
166
+ "dealer" => 4000,
167
+ "nondealer" => { "dealer" => 4000, "nondealer" => 2000 }
168
+ }
169
+ end
@@ -0,0 +1,86 @@
1
+ require_relative 'defines'
2
+ require_relative 'scoretable'
3
+
4
+ ##############################################
5
+ # Scoring class
6
+ ##############################################
7
+ module Reachy
8
+ module Scoring
9
+
10
+ # Point constants
11
+ P_BONUS = 300
12
+ P_RIICHI = 1000
13
+ P_TENPAI_3 = 2000
14
+ P_TENPAI_4 = 3000
15
+ P_START_3 = 35000
16
+ P_START_4 = 25000
17
+
18
+ # Convert han, fu input to hash keys
19
+ # Param: han - fixnum of han's
20
+ # fu - fixnum of fu's
21
+ # Return: list of keys
22
+ def self.to_keys(han,fu)
23
+ keys = []
24
+ if ((han<3 && fu>70) || (han==3 && fu>60) || (han==4 && fu>30) || (han==5))
25
+ keys = ["mangan"]
26
+ elsif (han==6 || han==7)
27
+ keys = ["haneman"]
28
+ elsif (han==8 || han==9 || han==10)
29
+ keys = ["baiman"]
30
+ elsif (han==11 || han==12)
31
+ keys = ["sanbaiman"]
32
+ elsif (han==13)
33
+ keys = ["yakuman"]
34
+ else
35
+ keys << "han_" + han.to_s
36
+ keys << "fu_" + fu.to_s
37
+ end
38
+ return keys
39
+ end
40
+
41
+ # Get Tsumo settlements
42
+ # Param: dealer - bool indicating if dealer won
43
+ # hand - list representing hand value (e.g. ["mangan"], [2,60])
44
+ # Return: hash of points
45
+ def self.get_tsumo(dealer,hand)
46
+ keys_h = if hand.first.instance_of?(String) then hand
47
+ else Scoring.to_keys(hand[0],hand[1]) end
48
+ if dealer
49
+ val = if keys_h.length == 2 then H_TSUMO["dealer"][keys_h[0]][keys_h[1]]
50
+ else H_TSUMO["dealer"][keys_h[0]] end
51
+ if not val then return nil end
52
+ return { "nondealer" => val }
53
+ else
54
+ val = if keys_h.length == 2 then H_TSUMO["nondealer"][keys_h[0]][keys_h[1]]
55
+ else H_TSUMO["nondealer"][keys_h[0]] end
56
+ return val
57
+ end
58
+ end
59
+
60
+ # Get Ron settlements
61
+ # Param: dealer - bool indicating if dealer won
62
+ # hand - list representing hand value (e.g. ["mangan"], [2,60])
63
+ # Return: fixnum of points
64
+ def self.get_ron(dealer,hand)
65
+ keys_h = if hand.first.instance_of?(String) then hand
66
+ else Scoring.to_keys(hand[0],hand[1]) end
67
+ val = if keys_h[1] then
68
+ H_RON[dealer ? "dealer" : "nondealer"][keys_h[0]][keys_h[1]]
69
+ else H_RON[dealer ? "dealer" : "nondealer"][keys_h[0]] end
70
+ return val
71
+ end
72
+
73
+ # Get Chombo settlements
74
+ # Param: dealer - bool indicating if dealer chombo
75
+ # Return: hash of points
76
+ def self.get_chombo(dealer)
77
+ if dealer
78
+ val = H_CHOMBO["dealer"]
79
+ if not val then return nil end
80
+ return { "nondealer" => val }
81
+ else
82
+ return H_CHOMBO["nondealer"]
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,156 @@
1
+ require 'io/console'
2
+
3
+ require_relative 'defines'
4
+
5
+ ##############################################
6
+ # Reachy utilities
7
+ ##############################################
8
+ module Reachy
9
+
10
+ # Prompt for user input with a message.
11
+ # If EOF is entered, aborts program.
12
+ # Param: message - string to display
13
+ # downcase - whether to downcase input
14
+ # Return: User input
15
+ # Note: always strips input!
16
+ def self.prompt(message, downcase=true)
17
+ print message
18
+ input = gets
19
+ goodbye if !input
20
+ if downcase
21
+ return input.strip.downcase
22
+ else
23
+ return input.strip
24
+ end
25
+ end
26
+
27
+ # Prompt for one character, downcased.
28
+ # If EOF is entered, aborts program.
29
+ # Param: message - string to display
30
+ # Return: User input character, downcased
31
+ def self.prompt_ch(message)
32
+ print message
33
+ input = STDIN.getch
34
+ goodbye if input == SIGINT_CH || input == EOF_CH
35
+ print input
36
+ return input.downcase
37
+ end
38
+
39
+ # Read all games in data dir, and store in @games array
40
+ def self.read_all_games
41
+ @games = []
42
+ Dir.foreach(File.expand_path("../../../data/", __FILE__)) do |filename|
43
+ # Skip . and .. dir entries, and trash dir
44
+ next if filename == '.' or filename == '..' or filename == "trash"
45
+
46
+ # Create game objects
47
+ game = Game.new(filename)
48
+ @games << game
49
+ end
50
+ end
51
+
52
+ # Print out all games in database
53
+ def self.display_all_games
54
+ if @games.empty?
55
+ puts " No game currently in database. Please add a new game."
56
+ puts nil
57
+ return false
58
+ end
59
+ @games.each_with_index do |game, index|
60
+ printf " %d) ", index + 1
61
+ game.print_title
62
+ end
63
+ return true
64
+ end
65
+
66
+ # Confirm game deletion
67
+ def self.confirm_delete(chosen_game)
68
+ printf "---> Deleting game \"%s\". This action cannot be undone.\n", chosen_game.filename
69
+ conf = prompt " Are you sure? (y/N) "
70
+ if conf == "y"
71
+ # Move associated json file to trash.
72
+ chosen_game.delete_from_disk
73
+ # Delete from @games array
74
+ @games.delete(chosen_game)
75
+ printf "*** Game \"%s\" deleted from database.\n\n", chosen_game.filename
76
+ return true
77
+ else
78
+ puts "You changed your mind? Fine.\n\n"
79
+ return false
80
+ end
81
+ end
82
+
83
+ # Ensure that the data and data/trash directory exist, if not create them
84
+ def self.ensure_data_dir
85
+ if not File.directory?(File.expand_path("../../../data/", __FILE__))
86
+ Dir.mkdir File.expand_path("../../../data/", __FILE__)
87
+ end
88
+ if not File.directory?(File.expand_path("../../../data/trash/", __FILE__))
89
+ Dir.mkdir File.expand_path("../../../data/trash/", __FILE__)
90
+ end
91
+ end
92
+
93
+ # Validate hand input
94
+ # Param: hand - string of hand value input
95
+ # Return: reformated hand value or empty list if input invalid
96
+ def self.validate_hand(hand)
97
+ split_hand = hand.split
98
+ hand = []
99
+ i = 0
100
+ flag = true
101
+ while i < split_hand.length # Did this C-style AKA imperatively.. how to ruby
102
+ if split_hand[i].match(/^\d+$/)
103
+ han = split_hand[i]
104
+ fu = split_hand[i+1]
105
+ if fu.match(/^\d+$/) && (fu.to_i==25 || fu.to_i%10 == 0)
106
+ hand << [han.to_i, fu.to_i]
107
+ i += 2
108
+ else
109
+ flag = false
110
+ hand = []
111
+ break
112
+ end
113
+ elsif L_HANDS.include?(split_hand[i])
114
+ hand << [split_hand[i]]
115
+ i += 1
116
+ else
117
+ flag = false
118
+ hand = []
119
+ break
120
+ end
121
+ end
122
+ if not flag
123
+ printf "Hand value malformed: \"%s\"\n", hand
124
+ end
125
+ return hand
126
+ end
127
+
128
+ # Display winners of every game
129
+ def self.display_all_winners
130
+ puts " Current winners:"
131
+ puts " ----------------"
132
+ @games.each do |game|
133
+ high_score = game.scoreboard.last.scores.values.max
134
+ winners = game.scoreboard.last.scores.select{ |player, score| score == high_score}
135
+ printf " * %s: %s - %d points\n", game.filename, winners.keys.join(", "), high_score
136
+ end
137
+ puts nil
138
+ end
139
+
140
+ # Call system cowsay if available
141
+ def self.cowsay
142
+ system("cowsay Bye!") if system("which cowsay >/dev/null 2>&1")
143
+ end
144
+
145
+ # Message to print when quitting program
146
+ def self.goodbye
147
+ puts "\n\n"
148
+ printf " -------------------------------\n" \
149
+ " | Thanks for flying reachy! |\n" \
150
+ " -------------------------------\n\n"
151
+ display_all_winners
152
+ cowsay
153
+ exit 0
154
+ end
155
+
156
+ end
data/lib/reachy.rb ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rubygems'
4
+ require 'date'
5
+ require 'fileutils'
6
+
7
+ require_relative 'reachy/game'
8
+ require_relative 'reachy/util'
9
+ require_relative 'reachy/main_menu'
10
+
11
+ ##############################################
12
+ # Main driver functionality
13
+ ##############################################
14
+ module Reachy
15
+
16
+ # Display initial screen (complete with banner, list of games)
17
+ def self.start_screen
18
+ # Display banner
19
+ File.open(File.expand_path("../banner", __FILE__), "r"){ |file| puts file.read }
20
+ puts nil
21
+
22
+ # Display all games in db
23
+ ensure_data_dir
24
+ read_all_games
25
+ puts "*** Current existing game(s) in database:"
26
+ puts nil if display_all_games
27
+
28
+ # Display main menu options
29
+ main_menu
30
+ end
31
+
32
+ end