timequiz 0.1.3

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.
Binary file
Binary file
@@ -0,0 +1,156 @@
1
+ =======================
2
+ TIMEQUIZ
3
+ =======================
4
+ ----------------------------------------
5
+ play a history quiz game
6
+ ----------------------------------------
7
+
8
+ SYNOPSIS
9
+ =======================
10
+ timequiz [options]
11
+
12
+ Called without any option, the game is started with the events that are included
13
+ in the installed program package. There are not many.
14
+
15
+ DESCRIPTION
16
+ =======================
17
+ The general idea is to put historical events in the right order. In the
18
+ beginning, a limited number of events (3 at the time of this writing) is
19
+ presented and you have to indicate the right order of these events. All the
20
+ following rounds will confront you with just 1 additional event and you must
21
+ find for the new event the right spot in the previously ordered list, i.e.
22
+ after one of the listed events or earlier than any of the known events. After
23
+ each round, the first one inclusive, your performance is evaluated. You can
24
+ then choose to continue with a new event or, if you like, read a short
25
+ description of any of the events, already in the list.
26
+
27
+ The game continues in this way until you push the 'q' button to quit or until
28
+ all the events that are known to the game, are listed.
29
+
30
+ You do not need to know it all
31
+ --------------------------------
32
+ Beware that to win a round, it is oftentimes not necessary to really know the
33
+ date of an event. Pure logic and reasonable guesses may be sufficient to find
34
+ the right spot within a historical context or to exclude events as too far in
35
+ the past or future of the currently handled event. Reading the descriptive
36
+ comments to an event may later help you get different events into context.
37
+
38
+ OPTIONS
39
+ =======================
40
+ **-a, --add** Add a new event
41
+
42
+ **-e, --event** [EVENT] Name of the new event
43
+
44
+ **-y, --year** [YEAR] Year of the new event
45
+
46
+ **-b, --background** [INFO] Background information for the new event
47
+
48
+ **-f, --file** [FILE] The file, where events are read from or written to
49
+
50
+ **-d, --debug** Be verbose
51
+
52
+ **-v, --version** Show program version
53
+
54
+ **-h, --help** Show a help text
55
+
56
+ The Options in detail:
57
+ ----------------------
58
+ -a --add
59
+ This option imposes that -e, -y, and -f be given, too. In consequence, it
60
+ will be considered superfluous and removed in future versions of the program.
61
+
62
+ -e --event
63
+ Name the event to add to the events-file. For this option to take effect, -a,
64
+ -y and -f are needed, too. Beware to enclose the value with quotes, like in, e.g.
65
+ --event "Some guy was born and something broke"
66
+
67
+ -y --year
68
+ Is followed by a year, like -y 1244
69
+
70
+ -b --background
71
+ Should be used to provide background-information to an event. While this
72
+ option is ... optional, the information will help solving quizzes and may be
73
+ educative to the player... do not abuse, though.
74
+ Example: -b "The phenomenon was bearing no significance whatsoever"
75
+
76
+ -f --file
77
+ Name the “events-file” which will be used for either creating the quizzes
78
+ randomly or adding events to an existing list of events. The file must be
79
+ readable to serve for a quiz and writable to accept new events. If it does
80
+ not exist, it is created and some exemplary events are included on top.
81
+ Example: --file ~/my_history_quiz
82
+
83
+ -d --debug
84
+ Be verbose. This switches on the output of debug-messages that have been left
85
+ in the program code. Probably useless.
86
+
87
+ -v --version
88
+ Shows the program version
89
+
90
+ -h --help
91
+ Shows the option-summary.
92
+
93
+
94
+ GAME EXAMPLE
95
+ =======================
96
+ Calling timequiz without arguments on the command-line, you are confronted with
97
+ three arbitrary, historical events, like in the following screen:
98
+
99
+ +---------------------------------------------------------------------------+
100
+ |Put the following events into the right chronological order (e.g.: 2 3 1). |
101
+ | |
102
+ |1) The Roman emperor Diocletian devides the empire in two |
103
+ |2) End of the "War of the mercenaries" |
104
+ |3) Destruction of Nimrod and Ninive by the Medians and Neo-Babylonians |
105
+ | |
106
+ |Available: 1, 2, 3) |
107
+ +---------------------------------------------------------------------------+
108
+
109
+ You type in the three numbers in the order that you consider chronologically
110
+ correct, like "321" (you do not have to push return after each number). The
111
+ game will respond by showing you the correct order of events with the
112
+ corresponding years and an evaluation of your input. You are also prompted to
113
+ decide if you want to play with a new arbitrary event or first be shown some
114
+ information about the listed events:
115
+
116
+ +------------------------------------------------------------------------------------------------------+
117
+ |Enter number for more information about an event, 'a' to play with one new, random event, 'q' to quit.|
118
+ +------------------------------------------------------------------------------------------------------+
119
+
120
+ If you push 'a', a new event is shown:
121
+
122
+ +----------------------------------------------------------------------------------------------------------+
123
+ |Indicate the event from the previous list, which precedes the following, or '0' (zero) to put it in front:|
124
+ | |
125
+ |The Italian painter Lorenzo Lotto dies. |
126
+ +----------------------------------------------------------------------------------------------------------+
127
+
128
+ You can now decide, which of the three previous events precedes the death of
129
+ the Italian painter and either put in the (current) number of that previous
130
+ event or the number 0 (zero) if you consider that Lorenzo Lotto died well
131
+ before any of the other events (which would, of course, be false in the
132
+ example). You have to push the return-button after your input, as it can
133
+ contain an arbitrary number of ciphers, later in the game.
134
+
135
+ Other Information
136
+ ====================
137
+ Development and source code
138
+ timequiz has been written in Ruby. As Ruby is an interpreted programming
139
+ language, the executable file and all those that it may refer to at one point
140
+ in time, are themselves the source-files of the current program-version. You
141
+ can open them in any text-editor to scrutinize the source-code. If you have
142
+ received the program as a Ruby-gem, you can also decompress a copy of the
143
+ gem-file with *tar -x*, then *tar -xzf*.
144
+
145
+ Bugs
146
+ At one time during the game, the list of already known events is incorrectly
147
+ wrapped and continues to be.
148
+
149
+ License
150
+ timequiz is distributed under the conditions of the GNU General Public
151
+ License, version 3.
152
+
153
+ Author
154
+ timequiz has been developed by Michael Uplawski
155
+ <michael.uplawski@uplawski.eu>
156
+
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+
4
+ =begin
5
+ /******************************************************************************
6
+ * Copyright © 2017-2017, Michael Uplawski <michael.uplawski@uplawski.eu> *
7
+ * *
8
+ * This program is free software; you can redistribute it and/or modify *
9
+ * it under the terms of the GNU General Public License as published by *
10
+ * the Free Software Foundation; either version 3 of the License, or *
11
+ * (at your option) any later version. *
12
+ * *
13
+ * This program is distributed in the hope that it will be useful, *
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16
+ * GNU General Public License for more details. *
17
+ * *
18
+ * You should have received a copy of the GNU General Public License *
19
+ * along with this program; if not, write to the *
20
+ * Free Software Foundation, Inc., *
21
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22
+ ******************************************************************************/
23
+ =end
24
+
25
+ require_relative 'constants'
26
+ require_relative 'logging'
27
+
28
+ class Adder
29
+ #@@events_file = File.dirname(__FILE__) << File::Separator << 'events.rb'
30
+ #@@events_backup = File.dirname(__FILE__) << File::Separator << 'bak_events.rb'
31
+ self::extend(Logging)
32
+ @@log = self::init_logger
33
+ # Do not present as 'Adder' on the command-line
34
+ self::log_label=$APPNAME
35
+
36
+ def self::add(options)
37
+ @log.debug('options are ' << options.to_s)
38
+ if options.file
39
+ @@events_file = options.file
40
+ @@events_backup = File.dirname(@@events_file) << File::Separator << 'bak_' << File.basename(@@events_file)
41
+ else
42
+ @log.error('To add events, you must name a file on the command-line. Aborting')
43
+ exit false
44
+ end
45
+ if(!options.event || !options.year)
46
+ @log.error("To add events, you must provide them on the command-line.\n\tPSE start the program with option -h or --help to see an option-overview.")
47
+ exit false
48
+ end
49
+
50
+ @@log.level = $LOG_LEVEL if $LOG_LEVEL
51
+ fields = [:event, :year, :background]
52
+ @log.debug('options are ' << options.to_s)
53
+ if options[:event] && options[:year]
54
+ if !options[:background]
55
+ @log.warn('Optional background information is missing')
56
+ bg = ''
57
+ else
58
+ bg = options.background
59
+ end
60
+
61
+ ev_def = "$events << [\"" << options.event << "\", " << options.year << ", \"" << bg << "\"]"
62
+ @log.debug('writing events-backup to ' << @@events_backup)
63
+ File.open(@@events_backup, 'w+') {|bak| bak.write( File.read(@@events_file))}
64
+ @log.debug('adding new event to the list: ' << ev_def)
65
+ File.open(@@events_file, 'a') {|evf| evf.puts(ev_def)}
66
+ @log.info('A new event has been added to ' << @@events_file << '.')
67
+ else
68
+ opts = options.to_h.keys
69
+ @log.error('Option missing: ' << fields.each {|f| opts.delete(f) }.join(', '))
70
+ exit false
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,85 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * ©2016-2017 Michael Uplawski <michael.uplawski@uplawski.eu> *
5
+ * *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
10
+ * *
11
+ * This program is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
23
+
24
+ require 'optparse'
25
+ require 'optparse/time'
26
+ require 'ostruct'
27
+ require_relative 'logging'
28
+ # require_relative 'translating'
29
+ require_relative 'constants'
30
+
31
+ class ArgParser
32
+ # Class level logger. This is a static class.
33
+ self.extend(Logging)
34
+ # self.extend(Translating)
35
+ @@log = init_logger()
36
+
37
+ # Returns a structure describing the options.
38
+ #
39
+ def self.parse(args)
40
+ # The options specified on the command line will be collected in
41
+ # <b>options</b>. No defaults. Most options are optional and do not
42
+ # have to be set at all.
43
+ # The others must be named for each transformation or be set in the
44
+ # configuration-file.
45
+ options = OpenStruct.new
46
+
47
+ op = OptionParser.new do |opts|
48
+ opts.on("-a", "--add", 'Add new event') do
49
+ options.add = 'add'
50
+ end
51
+
52
+ opts.on("-eEVENT", "--event=EVENT", 'Name of the event') do |ev|
53
+ options.event = ev
54
+ end
55
+ opts.on("-yYEAR", "--year=YEAR", 'Year of the event') do |year|
56
+ options.year = year
57
+ end
58
+ opts.on("-bINFO", "--background=INFO", 'Background information') do |info|
59
+ options.background = info
60
+ end
61
+ opts.on("-fFILE", "--file=FILE", 'The file, where events are read from') do |file|
62
+ options.file = file
63
+ end
64
+ opts.on("-d", "--debug", 'Be verbose') do
65
+ options.debug = 'debug'
66
+ end
67
+ opts.on("-v", "--version", 'Show program version') do
68
+ puts $APPNAME.dup << ", version " << $VERSION
69
+ exit true
70
+ end
71
+ end
72
+ begin
73
+ op.parse!(args)
74
+ rescue OptionParser::ParseError => er
75
+ msg = "ERROR! Unsuitable or incomplete program-arguments" << ": %s" %er.message
76
+ puts msg
77
+ puts "Start this program with parameter -h or --help to see the usage-message."
78
+ exit false
79
+ end
80
+
81
+ options
82
+ end # parse()
83
+
84
+ end
85
+
@@ -0,0 +1,104 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /******************************************************************************
5
+ * Copyright © 2014-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
+ # BusyIndicator provides a way to show 'activity' in a terminal-window, while
25
+ # the main thread does something else. For a usage example see the test-code at
26
+ # the bottom of this file and execute the file (e.g. ruby ./busy_indicator.rb)
27
+ class BusyIndicator
28
+ attr_writer :width
29
+ def initialize(start = true, width = nil)
30
+ # defaults
31
+ @width = width && width >= 3 ? width : 3
32
+ @sequence = %w"OOO ooo ___ ooo"
33
+ run if start
34
+ end
35
+
36
+ # change sequence for the following run().
37
+ def sequence=(seq)
38
+ @sequence = seq
39
+ @width = seq[0].length
40
+ end
41
+
42
+ # start busy-indicator with the current settings for width and sequence.
43
+ def run()
44
+ @thr = busy_indicator(@width) if !@thr || !@thr.alive?
45
+ end
46
+
47
+ # stop busy-indicator and show comment-string if given.
48
+ def stop(comment = nil)
49
+ @thr.terminate
50
+ @thr.join(0.1)
51
+ print ("\b" * @width)
52
+ print ("%+#{@width}s\n" %comment) if comment
53
+ end
54
+
55
+ # returns true or false, so that !stopped? == running?.
56
+ def running?
57
+ @thr.alive?
58
+ end
59
+
60
+ # returns true or false, so that !stopped? == running?.
61
+ def stopped?
62
+ !running?
63
+ end
64
+
65
+ private
66
+
67
+ # does it.
68
+ def busy_indicator(width)
69
+ tobj = Thread.new() do
70
+ loop do
71
+ @sequence.each do |s|
72
+ print "%+#{width}s" %s
73
+ sleep 0.1
74
+ print ("\b" * width)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ # ========== TEST =============
82
+ if($0 == __FILE__)
83
+ width = 20
84
+ 2.times do |i|
85
+ puts "I am busy, pse wait..."
86
+ thr = BusyIndicator.new(true, width)
87
+ sleep 3
88
+ # effect of comment != nil and comment == nil
89
+ thr.stop("Okay") if i == 0
90
+ thr.stop() if i != 0
91
+ end
92
+ bi = BusyIndicator.new(false)
93
+ # change sequence
94
+ bi.sequence = %w"E [ ( | ¦ ; , . o O D P F"
95
+ bi.run
96
+ sleep 3
97
+ bi.stop("Stopped")
98
+ # change width
99
+ bi.width = 8
100
+ bi.run
101
+ sleep 3
102
+ bi.stop("stopped again")
103
+ end
104
+
@@ -0,0 +1,73 @@
1
+ #encoding: UTF-8
2
+
3
+ =begin
4
+ /******************************************************************************
5
+ * Copyright © 2014-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
+ # Functions to apply colors to terminal output.
25
+ # This is stolen from the Internet and I have lost track of my own additions
26
+ # and modifications.
27
+
28
+ COLORS = {:default => 9, :black => 0, :red => 1, :green => 2, :yellow => 3, :blue => 4, :purple => 5, :cyan => 6, :white => 7 }
29
+
30
+ BG = 4
31
+ FG = 3
32
+ REGULAR = 0
33
+ BOLD = 1
34
+ UNDERLINE = 4
35
+ BLINK = 5
36
+ SWAP = 7
37
+ NEUTRAL = 0
38
+
39
+ STYLES = {:regular => REGULAR, :bold => BOLD, :underline => UNDERLINE, :blink => BLINK, :swap => SWAP, :neutral => NEUTRAL}
40
+
41
+ # Colorizes the given text. Color-code is either an escape-sequence or one of
42
+ # the symbols representing color-names in the COLORS hash.
43
+ def colorize(text, color_code)
44
+ if (COLORS.keys.include?(color_code) )
45
+ "\033[3#{COLORS[color_code]}m#{text}\033[0m"
46
+ else
47
+ "#{color_code}#{text}\033[0m"
48
+ end
49
+ end
50
+
51
+ def style(text, style_code)
52
+ "#{style_code}#{text}\033[0m"
53
+ end
54
+ # a function which allows to manipulate every known aspect of the ansi-output.
55
+ def colored_output(output_text, fg_color = :default, bg_color = :default, style = :regular , mode = :neutral )
56
+ "\033[%i;%i;%i%i;%i%im%s\033[0m" %[STYLES[mode.to_sym], STYLES[style.to_sym], FG, COLORS[fg_color.to_sym], BG, COLORS[bg_color.to_sym], output_text]
57
+ end
58
+
59
+ # convenience functions
60
+ def red(text); colorize(text, "\033[31m"); end
61
+ def green(text); colorize(text, "\033[32m"); end
62
+ def yellow(text); colorize(text, "\033[33m"); end
63
+ def purple(text); colorize(text, "\033[35m"); end
64
+ def cyan(text); colorize(text, "\033[36m"); end
65
+ def blue(text); colorize(text, "\033[34m"); end
66
+ def white(text); colorize(text, "\033[37m"); end
67
+
68
+ def black_on_white(text); colorize(colorize(text, "\033[30m"), "\033[47m");end
69
+ def white_on_black(text); colorize(colorize(text, "\033[37m"), "\033[40m");end
70
+
71
+ def bold(text); style(text, "\033[01m");end
72
+ def underline(text); style(text, "\033[04m");end
73
+