timequiz 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,219 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /***************************************************************************
5
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu>*
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ***************************************************************************/
22
+ =end
23
+
24
+ require_relative 'extstring'
25
+ require_relative 'user_input'
26
+ require_relative 'constants'
27
+
28
+ # Functions which create a user-interface in the terminal
29
+ module Console
30
+ # Some definitions which may change one day, become configurable one day,
31
+ # need to be accessed (one day) from somewhere else or not.
32
+ @@win_sequence = %w"won.. won.. Won.. WOn.. wON.. wON!. woN!! won!! won.! won.. _on.. __n.. ___.. ___.. w__.. wo_.. "
33
+ @@wait_sequence = %w"U\ V\ Y\ T\ |\ ¦\ :\ .\ _\ .\ o\ O\ "
34
+ @@fail_sequence = %w":-|\ :-|\ :-[\ :-[\ :-(\ :-(\ 8-(\ 8-(\ 8-(\ 8-(\ 8-(\ 8-(\ 8-(\ 8-(\ .... |... lo.. Los. LOso LOSe LOSE lOSE loSE lose"
35
+ @@points = 0
36
+ # start with some arbitrary events
37
+ def start_game
38
+ available = $events
39
+ clear
40
+ puts "Put the following events into the right chronological order (e.g.: 2 3 1)."
41
+ @m_events = Array.new
42
+ out = ''
43
+ $num_events.times do |i|
44
+ srand(Time.new.usec)
45
+ index = rand(available.length)
46
+ ev = Event.new(available.delete_at(index))
47
+ ev.disp_index = (i + 1)
48
+ @m_events << ev
49
+ out << (i + 1).to_s << ') ' << ev.title << "\n"
50
+ end
51
+ puts out.box(:left => 2)
52
+ response = nil
53
+
54
+ response = int_array_input($num_events, (1..$num_events) )
55
+ if response == :quit_game
56
+ score @@points
57
+ exit true
58
+ end
59
+
60
+ compare_order(response)
61
+ # good order of the response-array
62
+ if good_order(response)
63
+ @@points += $num_events
64
+ win
65
+ score(@@points)
66
+ else
67
+ lose
68
+ score(@@points)
69
+ end
70
+
71
+ # Start the loop. Add events as requested.
72
+ until @m_events.length == $MAX_NUM_EVENTS do
73
+ ui = ask_new_event
74
+ if ui == :quit_game
75
+ score @@points
76
+ exit true
77
+ end
78
+ if('a' == ui)
79
+ ev = new_event
80
+ if ev == :all_events_done
81
+ score(@@points)
82
+ exit true
83
+ end
84
+
85
+ # ------> unresolved trouble with 0-based array.indices. <----------
86
+ # 1) exclude new event from the choices (hence -1), allow 0 as 'earlier than any'.
87
+ r = int_input(0..(@m_events.length - 1) )
88
+ if r == :quit_game
89
+ score @@points
90
+ exit true
91
+ end
92
+ # User-input can be 0, which complicates the comparison with the
93
+ # 0-based event-array.
94
+
95
+ # 2) in the range of known events, if not 0 (hence 0 is allowed).
96
+ position_by_user(r)
97
+
98
+ # 4) 'order' must fit in between the indices of the event-array (0-based, hence -1. Again.)
99
+ ok = good_order(r - 1, ev)
100
+
101
+ sort_years(true)
102
+ # 5) show the resulting order as starting from 1, not 0.
103
+ show_correct_order
104
+ # <---------- This should be it. ------------>
105
+
106
+ if ok
107
+ @@points += 1
108
+ win
109
+ score(@@points)
110
+ else
111
+ lose
112
+ score(@@points)
113
+ end
114
+ else
115
+ detail( a2i(ui) )
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ def clear
122
+ system 'clear'
123
+ end
124
+
125
+
126
+ # add a new event to the game
127
+ def new_event
128
+ known_events = @m_events.collect {|ev| ev.title}
129
+ available = $events.collect {|ev| ev unless known_events.include?(ev[0]) }.compact
130
+ if !available || available.empty?
131
+ puts "\n\tNo more events available. Aborting. Bye"
132
+ puts
133
+ return :all_events_done
134
+ end
135
+ clear
136
+ out = ''
137
+ @m_events.each_with_index {|ev, i| out << (i + 1).to_s << ') ' << ev.title << "\n"}
138
+ puts out.box(:left => 2)
139
+
140
+ puts "Indicate the event from the previous list, which precedes the following, or '0' (zero) to put it in front:"
141
+ srand(Time.new.usec)
142
+ index = rand(available.length)
143
+ ev = Event.new(available[index])
144
+ @m_events << ev
145
+ puts ev.title.box(:color => :yellow)
146
+ return ev
147
+ end
148
+
149
+ def a2i(array)
150
+ UserInput::a2i(array)
151
+ end
152
+
153
+ def int_input(range = nil)
154
+ UserInput::int_input(range)
155
+ end
156
+ def int_array_input(len, range)
157
+ UserInput::int_array_input(len, range )
158
+ end
159
+
160
+ def ask_new_event
161
+ puts "\nEnter number for more information about an event, 'a' to play with one new, random event, 'q' to quit."
162
+ UserInput::input()
163
+ end
164
+
165
+ def score(pts)
166
+ puts ' (Current score: %i %s)' %[pts, (pts == 1 ? 'point' : 'points')]
167
+ end
168
+
169
+ def lose
170
+ cmt = 'You ' << red('lose.')
171
+ wait @@fail_sequence, 1, cmt
172
+ end
173
+
174
+ def win
175
+ cmt = 'You ' << cyan(' W O N !!')
176
+ wait(@@win_sequence, 1, cmt)
177
+ end
178
+
179
+ def show_correct_order
180
+ cmt = "\tThe right order is:\n" << @m_events.collect {|ev| (@m_events.index(ev) + 1).to_s << ') ' << ev.title << ' (' << ev.year.to_s << ')'}.join("\n").box()
181
+ wait(@@wait_sequence, 1, cmt)
182
+ end
183
+
184
+ # show information on an event
185
+ def detail(num)
186
+ if(0 != num && num <= @m_events.length)
187
+ det = @m_events.detect{|ev| ev.disp_index == num}.detail
188
+ if(det && !det.empty?)
189
+ puts ("\n" << num.to_s << ') ' << det).box(:color => :green)
190
+ else
191
+ puts " - No details known -"
192
+ end
193
+ end
194
+ end
195
+
196
+ def position_by_user(p)
197
+ if(p > 0)
198
+ puts "\n... You say: " << bold("after \"" << @m_events[p-1].title << "\"")
199
+ else
200
+ puts "\n... You say: " << bold("Earlier than any of the listed events")
201
+ end
202
+ end
203
+
204
+ def compare_order(response)
205
+ puts "\n... You say: " << bold(response.join(', '))
206
+ devents = @m_events.dup.sort {|f, s| f.year <=> s.year }
207
+ cmt = "\tThe right order is:\n" << devents.collect {|ev| ev.disp_index.to_s << ') ' << ev.year.to_s }.join("\n").box()
208
+ wait(@@wait_sequence, 1, cmt)
209
+ end
210
+
211
+ def wait(seq, sec, cmt)
212
+ bi = BusyIndicator.new(false)
213
+ bi.sequence = seq
214
+ bi.run
215
+ sleep sec
216
+ bi.stop(cmt)
217
+ end
218
+
219
+ end
@@ -0,0 +1,41 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /***************************************************************************
5
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu>*
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ***************************************************************************/
22
+ =end
23
+ require_relative 'logging'
24
+
25
+ $APPNAME='Timequiz'
26
+ $VERSION = '0.1.3'
27
+
28
+ # number of initial events
29
+ $num_events = 3
30
+ # maximal, final number of events per game
31
+ $MAX_NUM_EVENTS = 15
32
+ $LOG_LEVEL=Logger::INFO
33
+ $events = Array.new
34
+ # Constants for the Gtk-Interface
35
+ # EVENTS
36
+ CLICKED = 'clicked'
37
+ ACTIVATE = 'activate'
38
+ ENTER = 'enter-notify-event'
39
+ LEAVE = 'leave'
40
+ TOGGLED = 'toggled'
41
+
@@ -0,0 +1,41 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /******************************************************************************
5
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ******************************************************************************/
22
+ =end
23
+
24
+ # An object of this class is representing a historical event.
25
+ class Event
26
+
27
+ def initialize(ev)
28
+ @title = ev[0]
29
+ @year = ev[1]
30
+ @detail = ev[2]
31
+ @disp_index = 0
32
+ end
33
+
34
+ def to_s
35
+ str = '' << self.class.name << '{ title=' << @title << ', year=' << @year.to_s << ', detail=' << @detail << ', disp_index=' << @disp_index.to_s << '}'
36
+ end
37
+ attr_reader :title, :year, :detail
38
+ attr_accessor :disp_index
39
+ end
40
+ #EOF
41
+
@@ -0,0 +1,45 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /******************************************************************************
5
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ******************************************************************************/
22
+ =end
23
+
24
+ # All events known.
25
+ $events << ['Foundation of the UNESCO', 1946, '(4/11/1946) The United Nations Educational, Scientific and Cultural Organization wants to intensify the cooperation between peoples by developing education, science and culture']
26
+ $events << ['Invention of soap', -1500, '']
27
+ $events << ['First honeybees', -100000000, '']
28
+ $events << ['Artisanal production of glass', -2500, '']
29
+ $events << ['Invention of the door key', -2000, '']
30
+ $events << ['Invention of the solar clock', -1500, '']
31
+ $events << ['The Roman emperor Diocletian devides the empire in two', 185 , 'Caius Aurelius Valerianus Diocletianus also devides the power as he lets Maximian rule the western part of the Roman Empire and eight years later associates with each of the two "Augustus" one lesser colegue and designated successor of the title "Cæsar".']
32
+ $events << ['The American Saxophonist William John Coltrane is born', 1926, 'Coltrane played with Miles Davis and Thelonious Monk, then founded his own quartet. Major recordings: "My Favourite Things" (1960) and "A Love Supreme" (1964)']
33
+ $events << ['The French architect Jacques Lemercier becomes the principal architect of Louis XIII', 1618, 'Lemercier is considered one of the initiators of the French Classicism']
34
+ $events << ['The treaty of Greenville (USA/Ohio)', 1795, 'The British company of Ohio has ended the French occupation of the territory in 1763. Already under US administration since 1783, with the end of the Indian wars (Greenville, 1795), Ohio could become the 17th US-state in 1803.']
35
+ $events << ['"Each acceptor of electrons is an acid and each emitter a base" (Gilbert Newton LEWIS).', 1938, 'Lewis worked after 1913 on the chemical liaisons between non-metalic atoms. Since 1923 he elaborates a theory on acids and bases.']
36
+ $events << ['Destruction of Nimrod and Ninive by the Medians and Neo-Babylonians', -612, 'The medians were nomads and had become a thread to the Assyrian empire when their tribes united under king Phraorte. The Assyrians fought several preventive wars but in the end lost their empire to the victorious Medians.']
37
+ $events << ['French writer François Rabelais dies', 1553, 'Rabelais work show the humanists\' enthusiasm for philosophy, moral and knowledge of antiquity, the wisdom of which he admired. His freedom of expression, wealth of vocabulary and imagination still appear unequalled.']
38
+ $events << ['The anarchist Léon Czolgoscz assassinates the US-president William McKinley', 1901, 'President since 1896, McKinley advocates a strict economic protectionism. The victory in the Spanish-American war of 1898 assures his easy re-election in 1900. After the murder, McKinley is replaced by his vice-president Theodor Rosevelt']
39
+ $events << ['The German army under General Alexander von Kluck reaches the River Marne for the first time', 1914, '(05/09/1914) The first battle of the Marne took place in 1914, when a weakened German 1st army under General von Kluck was attacked and finally beaten by the 6th French army under Maunoury with decisive assistance by the British corps under John French.']
40
+ $events << ['The Italian painter Lorenzo Lotto dies', 1556, 'Unable to stand his ground against contemporaries like Raphael (in Rome) and Titian (in Venise), Lotto retreats to Bergamo, where he paints his big religious compositions between 1518 and 1528.']
41
+ $events << ['End of the "War of the mercenaries"', -238, 'Out of work after the first punic war and discriminated, the mercenaries of Carthago unite in -240 with other dissatisfied people under the Libyan Matho, besiege the city of Utica, but get finally massacred by an army under Hamilcar Barca and Hannon the Great.']
42
+ $events << ['Independence of the Republic of Nicaragua', 1821, 'Discovered by Christopher Columbus in 1502, the country was conquered by Gonzales d\'Avila who bate the Indian chief Nicarao. Since 1560, Nicaragua was part of the territory of Guatemala.']
43
+ $events << ['First siege of Vienna (Austria) by Süleyman the Magnificent', 1529, 'Under sultan Süleyman, the Ottoman empire won much territory and prospered in all respects. In October 1529, the Turkish army of 120000 men could though not break the resistance of the citizens of Vienna and finally had to retreat.']
44
+ $events << ['The Roman empress Galla Placidia dies', 450, 'Born around the year 390 as the daughter of Theodosius I, she was first married to Alaric\'s brother in law, Athaulf, king of the Visigoths, then to the future Constantius III, a general of her brother Honorius who inherited from her the title of "Augustus". After Honorius\' death and at the decision of Theodosius II, grandson of Theodosius I and emperor of the orient, Galla Placida governed the western empire for her six year old son Valentinian (the future Valentinian III).']
45
+ $events << ['Birth of Kathleen Mansfield', 1888, '(1888 Wellington, New-Zealand). Of vivid sensibility, Katherine Mansfield is the most representative novelist and poet of the era after World War I. Her novels had the biggest success in France. She died in 1923 on tuberculosis.']
@@ -0,0 +1,161 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /******************************************************************************
5
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ******************************************************************************/
22
+ =end
23
+
24
+ require_relative 'color_output'
25
+
26
+ # Functions which extend the String-class. Simply require this file to add
27
+ # capabilities to each String-object in your code.
28
+
29
+ # For historical reasons. Probably obsolete
30
+ if(! String.method_defined?(:end_with?))
31
+ class String
32
+ def end_with?(str)
33
+ isso = false;
34
+ if(str.respond_to?(:to_str) && self.include?(str))
35
+ isso = (slice(rindex(str), (size()-1)) == str)
36
+ end
37
+ return isso
38
+ end
39
+ end
40
+ end
41
+
42
+ # Not obsolete
43
+
44
+ class String
45
+
46
+ # Draws a box around the content.
47
+ # TODO: the :padding option is currently disabled as it confuses me.
48
+ def box(opt = {})
49
+ # ---------------
50
+ # Welcome to hell
51
+ # ---------------
52
+
53
+ color = opt[:color]
54
+
55
+ upleft = color ? colorize("\u250F", color) : "\u250F"
56
+ upright = color ? colorize("\u2513", color) : "\u2513"
57
+ downleft = color ? colorize("\u2517", color) : "\u2517"
58
+ downright = color ? colorize("\u251B", color) : "\u251B"
59
+
60
+ vert = color ? colorize("\u2503", color) : "\u2503"
61
+ hor = color ? colorize("\u2501", color) : "\u2501"
62
+
63
+ left = opt[:left]
64
+ top = opt[:top]
65
+ # padding = opt[:padding]
66
+
67
+ min_width = opt[:min_width]
68
+
69
+ size = `stty size`.split.map { |x| x.to_i }.reverse
70
+ left ||= 0
71
+ top ||= 0
72
+ # padding ||= 0
73
+
74
+ min_width ||= 15
75
+
76
+ # max_width is the width of the screen - left margin - 2x border
77
+ max_width = size[0] - left - 2
78
+
79
+ gsub!("\t", ' ')
80
+ width = max_width
81
+ # wrap lines, maybe
82
+ wrap(width , /^\d\)/)
83
+ # determine the width of the box
84
+ width = self.split("\n").max {|l1, l2| l1.chomp.length <=> l2.chomp.length}.length
85
+ width = [width, min_width].max
86
+
87
+ box = ''
88
+ # top margin
89
+ box << "\n" * top
90
+ # top border, left margin
91
+ box << ' ' * left << upleft.dup << hor.dup * width << upright.dup << "\n"
92
+ # top padding, left margin and so on ...
93
+ box << ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
94
+ # lines
95
+ self.split("\n").each do |line|
96
+ if(line && !line.empty?)
97
+ nl = ' ' * left << vert.dup << "%-#{width}s" %line
98
+ while(nl.length < width )
99
+ nl << ' '
100
+ end
101
+ nl << vert.dup << "\n"
102
+ else
103
+ nl = ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
104
+ end
105
+ box << nl
106
+ end
107
+ # bottom padding
108
+ box << ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
109
+ # bottom border
110
+ box << ' ' * left << downleft.dup << hor.dup * width << downright.dup
111
+ return box
112
+ end
113
+
114
+ def box!(opt = {})
115
+ self.replace(String.new(box(opt)))
116
+ end
117
+
118
+ # A wrap-function which works here, but may fail everywhere else.
119
+ def wrap(width, delimiter = "\n")
120
+ # YEAH. Ruby is crap because its regular expressions do not work as they
121
+ # should with special characters. And your coffee mug has a speech
122
+ # impediment. Face it!
123
+ words = self.scan(/\p{P}*[\wöÖüÜäÄßéèàôûùîçÇœæŒÆ]+\p{P}*/)
124
+
125
+ lines = []
126
+ lines << ''
127
+ li = 0
128
+ words.each do |w|
129
+ w.strip!
130
+ if( w.length + lines[li].length + 1 > width || w != words.first && w.match(delimiter) )
131
+ lines[li].squeeze!(' ')
132
+ lines << ''
133
+ li += 1
134
+ else
135
+ end
136
+ lines[li] << w
137
+ lines[li] << ' ' if w != words.last
138
+ end
139
+ self.replace(lines.join("\n"))
140
+ end
141
+
142
+ end
143
+
144
+ #--------------- TEST ---------------
145
+ if __FILE__ == $0
146
+ s = "Ein König mit Krone ist besser als ohne,\n\n(du Nase)!!".wrap(12)
147
+ puts s
148
+
149
+ s = "1) Ein Koenig mit Krone ist besser als ohne,\n\n(du Nase)!!\n2) We are not in Kansas anymore.\n3) Toto? Ich glaub, der Köter hieß Toto... ".wrap(12, /^\d/)
150
+ puts s
151
+
152
+
153
+ # puts "Ein Koenig mit Krone ist besser als ohne,\n\ndu Nase!!".box(:padding=>2)
154
+
155
+ s = "1) Didudel Doedel didödeledel dödeldödel dödeldödel du dödel. DOEDEL !\n"
156
+ s << "2) Man gab uns mancherlei auf Erden.\nZum Denken gab man uns die Stirn."
157
+ s << "2a) Man gab uns Herz- und Leibbeschwerden.\nDoch auch den Himmel und den Zwirn."
158
+ s << "3) Himmel, Ding und Zwirn."
159
+ s.wrap(12, /\d\)/)
160
+ puts s.box(:min_width=>20, :left => 20)
161
+ end