├── Readme.md ├── kernel ├── Readme.md ├── forth.ini └── kernel.elf ├── mcal ├── FACTS.TXT ├── MCAL.4TH ├── Readme.md └── screenshots │ ├── mcaldetail.png │ └── mcalmain.png └── wikiwriter ├── DATA ├── DESC.TXT ├── FEATURES.TXT ├── FORMS.TXT ├── ISSUES.TXT ├── JOBS.TXT ├── LOCS.TXT ├── PLACES.TXT ├── SPLASH1.IMG ├── SPLASH2.IMG ├── THEMES.TXT └── WANTS.TXT ├── ImageConverter.java ├── Readme.md ├── bootmenu.4th ├── screenshots ├── writerexample.png └── writerstart.png └── wikiwriter.4th /Readme.md: -------------------------------------------------------------------------------- 1 | Wikireader Adventures 2 | ===================== 3 | The [Wikireader](https://github.com/wikireader/wikireader) is a small, inexpensive device intended for browsing an offline snapshot of Wikipedia. It has four hardware buttons, a touchscreen, a 240x208 monochrome LCD display, a MicroSD card slot, a fairly powerful Epson [S1C33E07](http://www.epsondevice.com/webapp/docs_ic/DownloadServlet?id=ID000410) 32-bit SoC and best of all it runs Forth! The device was designed to use Forth for factory tests, but with very simple alterations to the included software it can be made to run custom applications from source files stored on the MicroSD card. 4 | 5 | On two occasions I have written personalized "desk accessories" for this platform. This repository is intended to gather together the materials for those projects as well as some of the reasoning behind their creation. Perhaps some day you might have a useful application idea for this or a similar device? 6 | 7 | Development Tools 8 | ----------------- 9 | Technically all you need to write Wikireader applications in Forth is a microSD reader, a computer, a Wikireader and nerves of steel. Thankfully, you can mitigate the pain of trial-and-error testing by taking advantage of the [Wikireader Simulator](http://createuniverses.blogspot.com/2011/03/wikireader-forth-simulator.html). Windows-specific source code is included, but I have found that it works just fine in Wine on a 32-bit Linux VM. If you have a serial interface available you can access some pins in the Wikireader battery compartment to enjoy wondrous "println debugging" facilities on the device itself. The Wikireader Github Wiki (phew) provides the [bootstrap source](https://github.com/wikireader/wikireader/blob/master/samo-lib/forth/ansi-forth.fs) for the onboard Forth interpreter, which is the best reference to the vocabularies available for accessing built-in hardware. 10 | 11 | The simulator uses a slightly different configuration of [Ficl](http://www.forth.org/ficl.html) than that on the device and some subtleties of the hardware simulation are likewise inaccurate, but it can get your code a long way toward working correctly on the device. A few "gotchas" I have encountered: 12 | 13 | - The Wikireader forth interpreter will crash on any source files which contain tab (`\t`) characters. Make sure you configure your text editor appropriately. 14 | 15 | - The simulator has a definition for the primitive `move` in its startup file. The Wikireader does not define this word- I recommend instead making your programs rely on the `cmove` primitive. The simulator doesn't define `cmove`, so you might want to add `: cmove move ;` to its startup file. 16 | 17 | - While working with file I/O I found that while on the simulator I can successfully use `open-file` in `w/o` mode to create and open a file that does not already exist, this operation will fail on the Wikireader. Calling `create-file` first works correctly on both the simulator and the device. There are probably more wrinkles and minor differences here, but this is the difference that actually bit me. 18 | 19 | - There is no way to generate a power-button keypress from the simulator. You can poll this in software for short presses. (A 3-second press will force the device to power off.) 20 | 21 | - The Wikireader's interpreter does not permit the word `s"` to be used in immediate mode; it must be used from within a word definition. 22 | 23 | Deploying your Code 24 | ------------------- 25 | Out of the box, the Wikireader has a file named "forth.elf" on its MicroSD card. Rename this to "kernel.elf" and it will run at power-on, executing a file named "forth.ini" from the card. All other files can be deleted if you wish. Consider backing up the contents of the card before you do any screwing around. I have included a copy of the forth interpreter binary renamed as "kernel.elf" in this repository for your convenience. I make no claims of ownership of this binary. 26 | 27 | License 28 | ------- 29 | With the exception of the kernel binary available in this repository, all documentation, source code and data is hereby released under the WTFPL license: 30 | 31 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 32 | Version 2, December 2004 33 | 34 | Copyright (C) 2004 Sam Hocevar 35 | 36 | Everyone is permitted to copy and distribute verbatim or modified 37 | copies of this license document, and changing it is allowed as long 38 | as the name is changed. 39 | 40 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 41 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 42 | 43 | 0. You just DO WHAT THE FUCK YOU WANT TO. 44 | -------------------------------------------------------------------------------- /kernel/Readme.md: -------------------------------------------------------------------------------- 1 | Kernel 2 | ====== 3 | Since the Wikireader is no longer supported and it is difficult to find binaries for the device online, I have included a copy of the compiled Forth kernel as distributed with 2011 Wikireaders. I make no claims of ownership of this binary. The complete source code for this binary and its associated documentation may be found at the [Wikireader](https://github.com/wikireader/wikireader) Github page. 4 | 5 | If placed on a MicroSD card at device startup, this will execute code in "forth.ini" which in turn may load and execute other forth code. 6 | -------------------------------------------------------------------------------- /kernel/forth.ini: -------------------------------------------------------------------------------- 1 | include bootmenu.4th 2 | -------------------------------------------------------------------------------- /kernel/kernel.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/kernel/kernel.elf -------------------------------------------------------------------------------- /mcal/FACTS.TXT: -------------------------------------------------------------------------------- 1 | Sharks don't have swimbladders. Their bouyancy comes from oil stored in their liver and their cartilage, which has half the density of bone. 2 | The name "millipede" literally means thousand-foot, but known species have at most 750. Most millipedes have 36 to 400 legs. 3 | Pill bugs, such as Armadillidium vulgare, are not insects- they are isopods, an order of crustaceans. 4 | Japanese spider crabs have a leg span of up to 12.5 feet and can weigh up to 44lbs. They are described as having a gentle disposition. 5 | While their diet is composed of 99% bamboo, wild giant pandas have been known to eat other grasses, wild tubers, birds, rodents or carrion. 6 | Orca whales have been known to fight sharks by holding them upside down, inducing tonic immobility and in some cases suffocation. 7 | Border Collies are often cited as the most intelligent dog breed. In January 2011, a Border Collie was reported to have learned 1,022 words and acts consequently to human citation of those words. 8 | The giant panda's paw has five fingers and an additional "thumb" formed from a modified sesamoid bone. 9 | About 1 in 500 male narwhals grows two tusks. Only 15 percent of female narwhals grow tusks at all, and there is only one recorded case of a female with two tusks. 10 | Some species of starfish start life as males and become females as they mature. In Nepanthia belcheri, a large female can split in half, resulting in two males. 11 | Sloth fur grows away from the extremities to provide protection from the elements while hanging upside down. It is often colonized by symbiotic cyanobacteria which provide camoflage. 12 | Anteaters are toothless and digest their prey using a modified gizzard-like stomach, aided by ingested sand and dirt. They also do not produce stomach acid, instead using the formic acid in their prey. 13 | The Textile Cone sea snail has a shell which grows in a pattern resembling that of the rule 30 cellular automaton. The similar rule 110 is turing-complete. 14 | The chicken is one of the most common and widespread domestic animals, with a population of more than 24 billion in 2003. There are more chickens in the world than any other species of bird. 15 | Brine shrimp eggs can survive temperatures of liquid air (-310F) and some can survive above boiling temperature (221F) for up to two hours. 16 | The Lammergeier, or Bearded Vulture, lives on a diet of 85-90% bone marrow. Its stomach acid has an estimated Ph of 1 and can dissolve large bones in about 24 hours. 17 | Camel Spiders are actually tail-less scorpions. It has been theorized that the "mice" referred to in the Old Testament were these creatures. 18 | The coconut crab is the largest land-living arthropod in the world, with a weight of up to 9lbs. It breathes with simple lungs and unlike most crabs can drown if immersed in water. 19 | The olfactory bulb in dogs is roughly forty times bigger than the olfactory bulb in humans, relative to total brain size, with 125 to 220 million smell-sensitive receptors. 20 | Deinococcus radiodurans is an extremophilic bacterium, and the world's most radioresistant organism. It can survive over 1000 times a human-lethal dose of ionizing radiation. 21 | Raccoon paws are covered in a horny layer which softens when exposed to water. They often rub items underwater to examine them by touch, giving the appearance of washing their food. 22 | Hedgehogs are birthed with a protective membrade covering their quills, which dries and shrinks over the next several hours. 23 | The rooster serves as a tangible vessel of christ for some as in the gospel of Matthew (26:74-75), Mark (14:71-72) and Luke (22:60-61) in the New Testament with Christ speaking through the cock. 24 | In experiments, rats have demonstrated altruistic behavior. When presented with chocolate chips and caged rats, test subjects would first free the other rat and then share the food. 25 | Penguins are countershaded for camoflage- a predator looking up from below has difficulty distinguishing their white belly from the reflective surface of water, and their dark back plumage conceals them from above. 26 | Mantises, sometimes called "praying mantises", are closely related to cockroaches. Orchid Mantises have been observed displaying paternal care by guarding their eggs, which is unusual among mantids. 27 | Skunk spray is composed of 2-butene-1-thiol, 3-methyl-1-butanethiol, and 2-quinolinemethanethiol. These compounds are detectable by the human nose at concentrations of 10 parts per billion. 28 | Some aphids have telescoping generations- females have a daughter within them (a genetic clone) which is also in the process of producing her own daughter. 29 | The Driver ant's jaws are extremely powerful and can retain their grip even when the ant is torn in half. East African soldiers sometimes use the ants as makeshift surgical staples to hold wounds together. 30 | Unlike horses, oxen are not easily able to balance on three legs while a farrier shoes the fourth. In England, shoeing was accomplished by throwing the ox to the ground and lashing all four feet to a heavy wooden tripod. 31 | The Talmud speaks of learning "courtesy toward one's mate" from the rooster. This might refer to the fact that when a rooster finds something good to eat, he calls his hens to eat first. 32 | Fossil studies suggest that the domestication of dogs took place between 14,000 and 31,700 years ago. In 2001 there were estimated to be 400 million dogs in the world. 33 | The pistol shrimp snaps a specialized claw shut to create a cavitation bubble which reaches speeds of 60 miles per hour and releases a sound reaching 218 decibels. The pressure is strong enough to kill small fish. 34 | Most attempts at training zebras for riding have failed, due to their tendency to panic. In 1907, Rosendo Ribeiro, the first doctor in Nairobi, Kenya, used a riding zebra for house calls. 35 | Baboons are able to acquire orthographic processing skills, which form part of the ability to read. 36 | In 2003, researchers found one species of dung beetle navigates by using polarization patterns in moonlight. The discovery is the first proof any animal can use polarized moonlight for orientation. 37 | The classification of batoids is currently undergoing revision; however, molecular evidence refutes the hypothesis that skates and rays are derived sharks. 38 | Because of their slow metabolism, large komodo dragons can survive on as little as 12 meals a year, but can eat up to 80% of their body mass in one sitting. 39 | In April and May, alligators form so-called "bellowing choruses". Large groups of animals bellow together for a few minutes a few times a day, usually one to three hours after sunrise. 40 | An elephant's trunk contains up to 150,000 separate muscle fascicles and is capable of storing 2.2 gallons of water or cracking a peanut shell without breaking the seed. 41 | Rattlesnakes are able to detect thermal radiation emitted by warm-blooded organisms in their environment and can detect temperature changes of 0.003C or less in its immediate surroundings. 42 | The box jellyfish has 24 eyes, two of which are capable of seeing color, and four parallel information processing areas or rhopalia that act in competition. 43 | The stoplight loosejaw has a unique vision system which uses a derivative of chlorophyll as a photosensitizer that absorbs long-wave light and then indirectly stimulates the fish's two visual pigments. 44 | Pigeons have no gall bladders. Some medieval naturalists concluded they have no bile (gall), which in the medieval theory of the four humours explained the allegedly sweet disposition of doves. 45 | Beavers practice alloparental care, in which an older sibling may take over the parenting duties if the original parents die. This behavior is seen in many other animal species such as the elephant and fathead minnow. 46 | Skinks in the genus Prasinohaema have green blood due to a buildup of the waste product biliverdin. 47 | The skin of naked mole rats lacks a key neurotransmitter that is responsible in mammals for sending pain signals to the central nervous system. The naked mole rats feel no pain when they are exposed to acid or capsaicin. 48 | The total brain-to-body mass ratio of crows is equal to that of great apes and cetaceans, and only slightly lower than in humans. 49 | Giant clams live in symbiosis with photosynthetic algae that grow in their tissues. Adult clams get 70-100% of their nutrients from the algae and the rest from filter feeding. 50 | The blobfish lives at depths between 2,000 and 3,900 ft where the pressure is several dozen times higher than at sea level. Their flesh is primarily a gelatinous mass with a density slightly less than water, giving them bouyancy. 51 | The severed head of a cockroach is able to survive and wave its antennae for several hours, or longer when refrigerated and given nutrients. 52 | The silk moth- the adult form of the silkworm- is unable to fly and has reduced mouthparts which are incapable of feeding. 53 | In 2011, cicadas were incorporated into a single batch of ice cream in Columbia, Missouri at Sparky's. They were advised by the public health department against making a second batch, a suggestion with which store owners complied. 54 | Aristotle wrote the earliest known inquiry into the natural history of eels, speculating that they were born of "earth worms", which he believed were formed of mud, growing from the "guts of wet soil". 55 | Many earthworms can eject coelomic fluid through pores in the back in response to stress; Australian Didymogaster sylvaticus (known as the "blue squirter earthworm") can squirt fluid as high as 12 inches. 56 | G.E. Gates spent 20 years studying regeneration in a variety of earthworms, showing that it is theoretically possible to grow two whole worms from a bisected specimen in certain species. 57 | The naked mole rat and the Damaraland mole rat are the only known eusocial mammals. Only one female (the queen) and one to three males reproduce, while the rest of the members of the colony function as workers. 58 | Although hippos lie close to each other, they do not seem to form social bonds except between mothers and daughters, and they are not social animals. The reason they huddle close together is unknown. 59 | In 1932 the Australian army attempted to cull Emu populations in what came to be known as the Great Emu War. After expending 2,500 rounds of ammunition over six days the death toll was "perhaps a dozen birds". 60 | A termite queen can live for 45 years, producing 20,000 to 30,000 eggs a day. Freshly hatched young appear as tiny termites that grow without significant morphological changes. 61 | Betta Splendens females frequently eat their own eggs shortly after spawning. For this reason, males chase females away and carefully guard the bubble nest they construct to protect them as they incubate. 62 | The silver fox was domesticated in Russia after a 45-year selective breeding program, which also resulted in traits appearing that are frequently seen in domestic animals, such as pigmentation changes, floppy ears, and curly tails. 63 | Many earwig species display maternal care, which is uncommon among insects. Female earwigs may care for their eggs, and even after they have hatched as nymphs will continue to watch over offspring until their second molt. 64 | Male honey bees are produced from unfertilized eggs, so represent only the DNA of the queen that laid the eggs- they have only a mother. They also lack stingers. 65 | The aptly-named hercules beetle can reach over 6.75 inches in length and can lift more than 850 times their own weight. 66 | -------------------------------------------------------------------------------- /mcal/MCAL.4TH: -------------------------------------------------------------------------------- 1 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 2 | \ 3 | \ MCal 4 | \ 5 | \ A page-a-day calendar written 6 | \ in Ficl-Forth for the WikiReader. 7 | \ 8 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 9 | 10 | decimal lcd-cls 1 1 lcd-at-xy 76 lcd-emit 11 | 12 | : inc dup @ 1+ swap ! ; 13 | : dec dup @ 1- swap ! ; 14 | 15 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 16 | \ 17 | \ Higher-Level graphics routines: 18 | \ 19 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 20 | 21 | : lcd-column ( -- n ) lcd-x @ font-width / ; 22 | : lcd-back ( -- ) -8 0 lcd-move-rel ; 23 | 24 | : fillbox ( w h -- ) 25 | lcd-x @ swap 26 | ( w x h ) 27 | 0 do 28 | over 1- 0 lcd-line-rel 29 | dup lcd-x ! 30 | lcd-y inc 31 | loop 32 | 2drop 33 | ; 34 | 35 | 79 lcd-emit 36 | 37 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 38 | \ 39 | \ Persistence: 40 | \ 41 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 42 | 43 | variable date-buffer 44 | : date-file s" DATE.TXT" ; 45 | 46 | : save-date ( n -- ) 47 | date-buffer ! 48 | date-file delete-file drop 49 | date-file w/o create-file 0= if 50 | \ we successfully opened the file 51 | >r date-buffer 1 cells r> dup >r write-file 52 | 53 | \ if the write fails, just give up 54 | drop r> close-file drop 55 | else 56 | drop 57 | then 58 | ; 59 | 60 | : load-date ( -- n ) 61 | date-file r/o open-file 0= if 62 | \ we successfully opened the file 63 | >r date-buffer 1 cells r> dup >r read-file 64 | 65 | \ return what's in our buffer even if read fails 66 | 2drop date-buffer @ r> close-file drop 67 | else 68 | drop 0 69 | then 70 | ; 71 | 72 | 65 lcd-emit 73 | 74 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 75 | \ 76 | \ Calendar Logic: 77 | \ 78 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 79 | 80 | variable selected 2 selected ! 81 | variable date 0 date ! 82 | 83 | variable thisYear 84 | variable thisMonth 85 | variable thisDay 86 | variable thisFirst 87 | variable thisMonthDays 88 | 89 | create monthDays 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 , 90 | 91 | : leapyear? ( year -- flag ) 92 | dup 400 mod 0= if drop true exit then 93 | dup 4 mod 0= swap 100 mod 0<> and 94 | ; 95 | 96 | : days-in-month ( -- days ) 97 | thisYear @ thisMonth @ 98 | 12 mod dup cells monthDays + @ 99 | swap 1 = if over leapyear? if 1+ then then 100 | nip 101 | ; 102 | 103 | : reset-date ( -- ) 104 | 2014 thisYear ! 105 | 0 thisMonth ! 106 | 0 thisDay ! 107 | 2 thisFirst ! 108 | days-in-month thisMonthDays ! 109 | ; 110 | 111 | : step-date ( -- ) 112 | thisDay inc 113 | thisDay @ thisMonthDays @ < if exit then 114 | 115 | thisFirst @ thisMonthDays @ + 7 mod thisFirst ! 116 | 0 thisDay ! thisMonth inc days-in-month thisMonthDays ! 117 | thisMonth @ 12 < if exit then 118 | 119 | 0 thisMonth ! thisYear inc 120 | ; 121 | 122 | : set-date ( n -- ) 123 | date ! reset-date 124 | date @ 0 ?do step-date loop 125 | ; 126 | 127 | 68 lcd-emit 128 | 129 | : step-to ( day year month -- ) 130 | \ sanity check month and carry years as needed: 131 | dup 11 > if drop 1+ 0 then 132 | dup 0 < if drop 1- 11 then 133 | \ sanity check year and clamp as needed: 134 | over 2014 < if 2drop 2014 0 then 135 | begin 136 | over thisYear @ = 137 | over thisMonth @ = 138 | and if 139 | 2drop 140 | \ sanity check day, clamping as needed: 141 | dup days-in-month > if drop days-in-month then 142 | 0 ?do date inc step-date loop 143 | 144 | date @ save-date exit 145 | then 146 | date inc step-date 147 | again 148 | ; 149 | 150 | : set-day ( day -- ) 151 | \ keep year and month 152 | thisYear @ thisMonth @ 153 | 0 date ! reset-date 154 | step-to 155 | ; 156 | 157 | : next-date ( -- ) 158 | selected @ 0= if 159 | thisDay @ 160 | thisYear @ 1+ 161 | thisMonth @ 162 | step-to exit 163 | then 164 | selected @ 1 = if 165 | thisDay @ 166 | thisYear @ 167 | thisMonth @ 1+ 168 | step-to exit 169 | then 170 | date inc step-date date @ save-date 171 | ; 172 | 173 | : prev-date ( -- ) 174 | \ the universe begins on january 1st 2014: 175 | date @ 0= if exit then 176 | 177 | selected @ 0= if 178 | thisDay @ 179 | thisYear @ 1- 180 | thisMonth @ 181 | reset-date 0 date ! step-to exit 182 | then 183 | selected @ 1 = if 184 | thisDay @ 185 | thisYear @ 186 | thisMonth @ 1- 187 | reset-date 0 date ! step-to exit 188 | then 189 | date @ 1- set-date date @ save-date 190 | ; 191 | 192 | 73 lcd-emit 193 | 194 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 195 | \ 196 | \ Fact Storage: 197 | \ 198 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 199 | 200 | create fact-buffer 1024 allot 201 | create fact-data 366 1024 * allot 202 | create fact-entries 366 2 * cells allot 203 | variable fact-count 0 fact-count ! 204 | variable fact-head fact-data fact-head ! 205 | 206 | : load-fact ( addr len -- ) 207 | fact-count @ 366 = if 208 | 2drop ." Fact capacity exceeded." cr exit 209 | then 210 | 2dup >r fact-head @ r> cmove 211 | nip fact-head @ 212 | over fact-head @ + fact-head ! 213 | fact-count @ 2 * cells fact-entries + 214 | swap over ! 1 cells + ! fact-count inc 215 | ; 216 | 217 | : load-facts ( -- ) 218 | s" FACTS.TXT" r/o open-file 0= if 219 | >r 220 | begin 221 | fact-buffer 1024 r> dup >r read-line 222 | 0= if 223 | 0= if drop r> close-file drop exit then 224 | fact-buffer swap load-fact 225 | else 226 | drop drop r> close-file drop exit 227 | then 228 | again 229 | else 230 | drop ." Unable to load fact database!" cr 231 | then 232 | ; 233 | 234 | : get-fact ( index -- addr len ) 235 | fact-count @ mod 236 | 2 * cells fact-entries + 237 | dup @ swap 1 cells + @ 238 | ; 239 | 240 | 78 lcd-emit 241 | 242 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 243 | \ 244 | \ Fact Display: 245 | \ 246 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 247 | 248 | variable text-addr 249 | variable text-len 250 | variable word-addr 251 | variable word-len 252 | 253 | : next-word ( -- word-addr word-len ) 254 | text-addr @ word-addr ! 255 | 0 word-len ! 256 | begin 257 | \ if we've reached a whitespace or eos, break. 258 | text-addr @ c@ 32 = text-len @ 1 < or if 259 | text-addr inc 260 | text-len dec 261 | word-addr @ 262 | word-len @ 263 | exit 264 | then 265 | text-addr inc 266 | text-len dec 267 | word-len inc 268 | again 269 | ; 270 | 271 | : text-wrap ( addr len -- ) 272 | 1 5 lcd-at-xy lcd-black 273 | text-len ! 274 | text-addr ! 275 | begin 276 | text-len @ 1 < if exit then 277 | next-word 278 | dup 1 + lcd-column + lcd-text-columns 1 - > if lcd-cr then 279 | 8 0 lcd-move-rel 280 | lcd-type 281 | again 282 | ; 283 | 284 | : draw-fact ( index -- ) 285 | lcd-white 286 | 1 3 lcd-at-xy s" Did you know...? " lcd-type 287 | get-fact text-wrap 288 | ; 289 | 290 | 71 lcd-emit 291 | 292 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 293 | \ 294 | \ Calendar Display: 295 | \ 296 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 297 | 298 | : .year ( n -- ) 299 | selected @ 0 = if lcd-white else lcd-black then 300 | lcd-space lcd-u. 301 | ; 302 | 303 | : .month ( n -- ) 304 | selected @ 1 = if lcd-white else lcd-black then 305 | s" JanFebMarAprMayJunJulAugSepOctNovDec" 306 | drop swap 12 mod 3 * + 3 lcd-space lcd-type lcd-space 307 | ; 308 | 309 | : .day ( n -- ) 310 | dup 10 mod 1 = over 11 <> and if lcd-u. lcd-back s" st " lcd-type exit then 311 | dup 10 mod 2 = over 12 <> and if lcd-u. lcd-back s" nd " lcd-type exit then 312 | dup 10 mod 3 = over 13 <> and if lcd-u. lcd-back s" rd " lcd-type exit then 313 | lcd-u. lcd-back s" th " lcd-type 314 | ; 315 | 316 | : box>day ( pos -- label ) 317 | dup thisFirst @ < if drop -1 exit then 318 | thisFirst @ - 319 | dup days-in-month > if drop -1 exit then 320 | ; 321 | 322 | : daybox-outline ( label pos -- ) 323 | dup 7 mod 32 * 7 + \ x 324 | swap 7 / 26 * 34 + \ y 325 | lcd-move-to lcd-black 326 | thisDay @ 1+ = >r 327 | 33 27 r> if fillbox else lcd-box then 328 | ; 329 | 330 | 46 lcd-emit 331 | 332 | : daybox-label ( label pos -- ) 333 | dup 7 mod 4 * 2 + \ x 334 | swap 7 / 2 * 3 + \ y 335 | lcd-at-xy 336 | dup thisDay @ 1+ = if lcd-white else lcd-black then 337 | dup 10 < if lcd-space then lcd-u. 338 | ; 339 | 340 | : daybox ( label pos -- ) 341 | 2dup 342 | over thisDay @ 1+ = if 343 | daybox-outline daybox-label else 344 | daybox-label daybox-outline then 345 | ; 346 | 347 | : xy>box ( x y -- pos ) 348 | over 7 < over 34 < or if 2drop -1 exit then 349 | 34 - 26 / dup 5 > if 2drop -1 exit then swap \ y 350 | 7 - 32 / dup 6 > if 2drop -1 exit then swap \ x 351 | 7 * + 352 | ; 353 | 354 | : draw-calendar ( -- ) 355 | lcd-clear-all 356 | 1 1 lcd-at-xy 357 | thisMonth @ .month 358 | selected @ 2 = if 359 | thisDay @ 1+ .day 360 | then 361 | 23 1 lcd-at-xy 362 | thisYear @ .year 363 | 364 | selected @ 2 = if 365 | date @ draw-fact 366 | else 367 | 42 0 do 368 | i box>day 369 | dup 0 > if i daybox else drop then 370 | loop 371 | then 372 | ; 373 | 374 | 46 lcd-emit 375 | 376 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 377 | \ 378 | \ The main program: 379 | \ 380 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 381 | 382 | : handle-buttons ( -- updated ) 383 | false 384 | button case 385 | button-power of endof 386 | button-left of prev-date true or endof 387 | button-right of next-date true or endof 388 | button-centre of selected @ 1 + 3 mod selected ! true or endof 389 | endcase 390 | ; 391 | 392 | : handle-touch ( -- updated ) 393 | ctp-pos 394 | over -1 = over -1 = and if 395 | 2drop false exit 396 | then 397 | 398 | selected @ 2 = if 399 | \ tapping on fact view returns to calendar view: 400 | 1 selected ! 401 | 2drop true exit 402 | then 403 | 404 | dup 34 < if 405 | drop 406 | selected @ 1 = if 407 | 160 > dup if 0 selected ! then exit 408 | then 409 | selected @ 0 = if 410 | 80 < dup if 1 selected ! then exit 411 | then 412 | drop false exit 413 | then 414 | 415 | xy>box dup 0 < if drop false exit then 416 | box>day 1- dup 0 < if drop false exit then 417 | 418 | dup thisDay @ = if 419 | 2 selected ! 420 | drop true exit 421 | then 422 | 423 | set-day true 424 | ; 425 | 426 | 46 lcd-emit 427 | 428 | : main ( -- ) 429 | load-facts 430 | load-date set-date 431 | ctp-flush 432 | key-flush 433 | draw-calendar 434 | begin 435 | false 436 | key? if key-flush then 437 | ctp-pos? if handle-touch or ctp-flush then 438 | button? if handle-buttons or button-flush then 439 | if draw-calendar then 440 | wait-for-event 441 | again 442 | ; 443 | 444 | main -------------------------------------------------------------------------------- /mcal/Readme.md: -------------------------------------------------------------------------------- 1 | MCal 2 | ==== 3 | MCal is a page-a-day calendar application which can load a database of fascinating facts from a text file called `FACTS.TXT`: 4 | 5 | ![main view](https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/master/mcal/screenshots/mcalmain.png) ![detail](https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/master/mcal/screenshots/mcaldetail.png) 6 | 7 | This program was written over the course of about two weeks. Some aspects of the design are rather crude and cobbled together. The lack of a real-time clock in the Wikireader seriously limits the utility of a program like this- while the device can remember what date was last viewed via a timestamp stored in a file called `DATE.TXT`, the user still needs to manually advance the page each day. 8 | 9 | The calendar logic is also implemented fairly crudely- when you step forward to a date it advances a series of registers one day at a time until it reaches the desired date. To move back, it resets to epoch (January 1st, 2014) and steps forward. Time moves slower the further you get from the epoch, and years take noticeably longer than months or days. Writing the code this way was fairly easy to verify, though, and while perhaps this is just validating my laziness I couldn't help but feel it produced a kind of poetic symbolism in its action. When I made the device I figured it would have a lifespan of a few years at most, and the algorithms employed are fast enough within that time range. Better than it ultimately needed to be. 10 | 11 | The word-wrapping routines for text display do a fairly good job, and I would later tweak and generalize them for my next project, the Wikiwriter. 12 | -------------------------------------------------------------------------------- /mcal/screenshots/mcaldetail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/mcal/screenshots/mcaldetail.png -------------------------------------------------------------------------------- /mcal/screenshots/mcalmain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/mcal/screenshots/mcalmain.png -------------------------------------------------------------------------------- /wikiwriter/DATA/DESC.TXT: -------------------------------------------------------------------------------- 1 | a run-down 2 | a neat and tidy 3 | a sunny and idyllic 4 | a shadowy and mysterious 5 | a crampt and stuffy 6 | a tacky, gaudily-decorated 7 | a long-abandoned 8 | a recently constructed 9 | a memorial 10 | a historic 11 | a cluttered and disorganized 12 | a strikingly modern 13 | a recent crime scene in a 14 | an impromptu meeting at a 15 | a raucous party at a 16 | an indie music concert at a 17 | a wiltingly humid 18 | a cold and gloomy 19 | a post-apocalyptic 20 | an undergound -------------------------------------------------------------------------------- /wikiwriter/DATA/FEATURES.TXT: -------------------------------------------------------------------------------- 1 | a gallant rogue 2 | self-insertion 3 | an unreliable narrator 4 | an unreliable editor 5 | anachronistic diction 6 | a character with tourette's syndrome 7 | anthropomorphic animal(s) which may not be real 8 | multiple flashbacks 9 | in media res 10 | a reverse-macguffin 11 | multiple narrators 12 | a chase scene 13 | a buddy-cop subplot 14 | a love triangle 15 | a series of rude fortune cookies 16 | organ transplants 17 | a scientific discovery that can lead only to ruin 18 | a scientific discovery that questions our perception of reality 19 | a scientific discovery that is, all things considered, pretty lame 20 | vigilante justice 21 | an author carrying out a writing prompt (roll again!) 22 | the olympics being basically horseshit 23 | a cat named "lint" 24 | sidekicks as heroes 25 | heroes as sidekicks 26 | first contact with a friendly alien race 27 | first contact with a hostile alien race 28 | robots as an analogy to god creating humanity 29 | robots as an analogy to underclasses 30 | robots, just because why not 31 | a world as portrayed in black and white segments of infomercials 32 | a world as portrayed in bollywood musicals 33 | a world as portrayed in 1800s science fiction 34 | the discovery that something we take for granted in life was imagined all along 35 | cryptocurrency 36 | cryptobiology 37 | ghouls and/or milk-steak 38 | a post-apocalypse 39 | a pre-aopcalypse 40 | an unlikable "main character" who is killed off and replaced 41 | a murderer with an outrageous gimmick 42 | the story from the villain's perspective 43 | settling a dispute via coin toss and/or rock paper scissors 44 | a dead parrot 45 | an unplanned pregnancy 46 | an agoraphobe 47 | external representations of inner struggles 48 | an ugly breakup 49 | a character who critiques the tropes of this genre 50 | a necromancer who solves murders 51 | the mundanity of office life 52 | an extended chess metaphor 53 | the maze as a motif 54 | blindness as a motif 55 | a play within a play 56 | time travel (back to the future 1 continuity model) 57 | time travel ("Primer" continuity model) 58 | time travel (inevitable past/present/future model) 59 | obvious retconning 60 | a comic miscommunication which could have easily been resolved with a cell phone call 61 | an online relationship gone horribly awry -------------------------------------------------------------------------------- /wikiwriter/DATA/FORMS.TXT: -------------------------------------------------------------------------------- 1 | a haiku 2 | a pastoral 3 | a sonnet 4 | an anaphora 5 | a cento 6 | an elegy 7 | a ghazal 8 | a pantoum 9 | a sapphic 10 | a triolet 11 | a blues poem 12 | a dramatic monologue 13 | an epistle 14 | a limerick 15 | a renga 16 | a tanka 17 | a ballad 18 | an epic 19 | a prose poem 20 | a free verse poem 21 | a fictional memoir 22 | a fictional autobiography 23 | a one-act play 24 | a soliloquy 25 | an essay 26 | a 5-paragraph essay (lol) 27 | an epigram 28 | a fable 29 | a bildungsroman 30 | an epistolary novel 31 | a historical novel 32 | a novel of manners 33 | a picaresque novel 34 | a social protest novel 35 | an allegory 36 | a comedy 37 | a farce 38 | a morality play 39 | a mystery 40 | a noh drama 41 | a tragedy 42 | a tragicomedy 43 | a romantic comedy 44 | a case report 45 | a chivalric romance 46 | a telephone transcript 47 | a court transcript 48 | a restaurant menu 49 | an imaginary novel foreward 50 | an imaginary novel appendix 51 | a fictional encylcopedia entry 52 | a tombstone inscription 53 | an obituary 54 | a letter to the editor 55 | an advice column 56 | a classified ad 57 | a cover letter -------------------------------------------------------------------------------- /wikiwriter/DATA/ISSUES.TXT: -------------------------------------------------------------------------------- 1 | you- yes, you reading this 2 | immense clumsiness 3 | a lack of intelligence 4 | a strong lisp 5 | crushing poverty 6 | family responsibilities 7 | fiscal responsibilities 8 | a lack of self-worth 9 | taking care of an old house 10 | inopportune narcolepsy 11 | a really bad sense of timing 12 | a complete lack of originality 13 | gutless cowardice 14 | sheer greed 15 | sheer laziness 16 | a mysterious curse 17 | two annoying children 18 | unpaid debts 19 | crippling alcoholism 20 | an inflated sense of self-worth 21 | picky eating 22 | arachnophobia 23 | dyslexia 24 | an eating disorder 25 | severe depression 26 | domestic abuse 27 | childhood trauma 28 | post-traumatic stress disorder 29 | schizophrenia 30 | a lousy sense of humor 31 | being a complete slob 32 | an obsession with collecting 33 | poor interpersonal skills 34 | a lack of applicable experience 35 | a misplaced sense of duty 36 | memory loss 37 | anger management issues 38 | problems with authority 39 | a desire to micromanage everything 40 | constant unwanted romantic advances 41 | a hyper-competitive childhood rival 42 | unjust laws (in their opinion, anyway) 43 | an inferiority complex 44 | manic depression 45 | insatiable hunger 46 | really shitty taste in friends 47 | racial profiling 48 | sex discrimination 49 | an overbearing boss 50 | overwhelming negative publicity 51 | mysterious circumstances of their birth 52 | a personal system of ethics 53 | religious stricture 54 | the loss of a precious heirloom 55 | an apocalyptic disaster 56 | a boring utopia 57 | those meddling kids 58 | a personal hero who turns out to be an asshole 59 | a personal hero who needs help themselves 60 | a draconian contract 61 | a community of mentally handicapped people 62 | rude neighbors 63 | a split personality disorder 64 | living a dual life 65 | vast geographic distances 66 | a crippling fear of the unknown -------------------------------------------------------------------------------- /wikiwriter/DATA/JOBS.TXT: -------------------------------------------------------------------------------- 1 | a miner 2 | a cobbler 3 | a computer programmer 4 | an actuary 5 | a stripper with a heart of gold 6 | a starving college student 7 | an aloof millionaire 8 | a dog-sized spider with human intelligence 9 | a down-and out bodyguard 10 | a personal trainer 11 | an artificial intelligence 12 | an average kindergardener 13 | a retired veteran 14 | a postal worker 15 | a receptionist 16 | a gardener 17 | a fast food manager 18 | a taxi driver 19 | a machinist 20 | a psychiatrist 21 | a diagnostician 22 | a hospice nurse 23 | a bricklayer 24 | a fisherman 25 | a horse surgeon 26 | a marathon runner 27 | a graduate school professor 28 | a photographer 29 | a museum director 30 | an aspiring actress 31 | a professional golfer 32 | a g-g-ghost 33 | a cantankerous octogenarian 34 | an animate pencil sharpener 35 | a small white widget on your desk with three buttons 36 | an inner-city landlord 37 | a cat burgular 38 | an advice columnist 39 | a meteorologist 40 | a civil engineer 41 | a washed-up indie musician 42 | a career politician 43 | a man of average intelligence 44 | a magical talking cat 45 | an isolated hermit 46 | a shipwrecked castaway 47 | an astronaut 48 | an online bully -------------------------------------------------------------------------------- /wikiwriter/DATA/LOCS.TXT: -------------------------------------------------------------------------------- 1 | apartment building 2 | barn 3 | mansion 4 | grocery store 5 | park 6 | mountain range 7 | forest path 8 | post office 9 | furniture store 10 | car dealership 11 | desert 12 | fancy restaurant 13 | pawn shop 14 | theater 15 | bar 16 | video rental shop 17 | construction site 18 | haberdashery 19 | dentist's office 20 | dungeon 21 | graveyard 22 | nuclear missile silo 23 | space station 24 | city 25 | domed city 26 | library 27 | witches hut 28 | catacomb 29 | bathroom -------------------------------------------------------------------------------- /wikiwriter/DATA/PLACES.TXT: -------------------------------------------------------------------------------- 1 | on mars 2 | in hoboken, new jersey 3 | in new york city 4 | in ancient mesopotamia 5 | in orem, utah 6 | in tokyo, japan 7 | somewhere in the pacific 8 | in the jurassic period 9 | during prohibition 10 | during the civil war 11 | in a faroff galaxy 12 | inside a black hole 13 | in los angeles, california 14 | in chicago, illinois 15 | in the wilds of alaska 16 | at the north pole 17 | deep beneath the ocean 18 | high above the clouds 19 | in paris, france 20 | in the great black swamp 21 | on the african savannah 22 | somewhere in the irish countryside 23 | somewhere in siberia 24 | in the stomach of an owl 25 | in an endless suburbia 26 | in boston, massachusetts 27 | five minutes from now 28 | 10 years from now 29 | in rural idaho 30 | near the amazon river basin 31 | near the grand canyon 32 | among the ruins of an ancient civilization 33 | in houghton, michigan 34 | in houston, texas 35 | in death valley national park 36 | on the coast of maine 37 | near an unstable fault line 38 | where a family of three mysteriously disappeared 39 | where a child was mauled by an unknown creature 40 | that is in the process of being sold 41 | that is in the process of being demolished 42 | above an indian burial ground 43 | straddling the international date line 44 | at the edge of a sheer cliff 45 | -------------------------------------------------------------------------------- /wikiwriter/DATA/SPLASH1.IMG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/wikiwriter/DATA/SPLASH1.IMG -------------------------------------------------------------------------------- /wikiwriter/DATA/SPLASH2.IMG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/wikiwriter/DATA/SPLASH2.IMG -------------------------------------------------------------------------------- /wikiwriter/DATA/THEMES.TXT: -------------------------------------------------------------------------------- 1 | the beauty of simplicity 2 | the effect of capitalism on the individual 3 | the necessity of change in power 4 | the conflict of change versus tradition 5 | the conflict of chaos and order 6 | the destruction of character 7 | the ciiiircle of liiiiife 8 | the coming of age 9 | nonverbal communication 10 | companionship as salvation 11 | the dangers of ignorance 12 | tragic death 13 | escapism 14 | disillusion and dreams 15 | everlasting love 16 | the evils of racism 17 | fading beauty 18 | fate and free will 19 | the pain and pleasure of growing up 20 | betrayal 21 | illusionment 22 | injustice 23 | isolationism 24 | motherhood 25 | fatherhood 26 | the power of names 27 | the complications of patriotism 28 | the power of words 29 | self-discovery 30 | social mobility 31 | totalitarianism 32 | the vulnerability of the strong 33 | social withdrawl 34 | the motif of harmful sensation 35 | the opposite of whatever the last one was -------------------------------------------------------------------------------- /wikiwriter/DATA/WANTS.TXT: -------------------------------------------------------------------------------- 1 | financial independence 2 | to travel the world 3 | to find love 4 | their dull life to be broken up with some excitement 5 | wealth and power 6 | an escape from the city life 7 | an escape from the country life 8 | an escape from a war-torn nation 9 | to be like their celebrity hero 10 | to kick a drug habit 11 | to close the book on a life of crime 12 | to spend more time with their family 13 | acceptance by their peers 14 | to get a more rewarding job 15 | to become a renowned criminal 16 | to fight crime 17 | to avenge the death of a loved one 18 | to murder a long-time rival 19 | to come up with an original idea 20 | to win a beauty pageant 21 | to mend their relationship with family 22 | world conquest 23 | the voices to stop talking to them 24 | some peace and quiet 25 | to find an obscure fast food product 26 | to overcome a crippling physical disability 27 | to change their appearance and start a new life 28 | to take advantage of the good will of others 29 | to live a normal life 30 | to pitch a hit screenplay 31 | to win the heart of a longtime crush 32 | to eradicate a disease 33 | to correct a bureaucratic error 34 | to discover the truth of an unsolved mystery 35 | a little house with a white picket fence 36 | to raise chickens 37 | casual sex 38 | recognition as a brilliant artist 39 | to get over a past relationship 40 | revenge for a forgotten slight 41 | to sell their house 42 | to start a successful business -------------------------------------------------------------------------------- /wikiwriter/ImageConverter.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.awt.image.*; 3 | import javax.imageio.*; 4 | 5 | public class ImageConverter { 6 | public static void main(String[] args) throws Exception { 7 | 8 | BufferedImage i = ImageIO.read(new File("SPLASH2.PNG")); 9 | DataOutputStream o = new DataOutputStream(new FileOutputStream(new File("SPLASH2.IMG"))); 10 | 11 | // 240x208 1 bit 12 | for(int y=0; y<208; y++) { 13 | for(int x=0; x<32; x++) { 14 | // each byte represents 8 pixels 15 | // image is logically padded to 32 bytes/row 16 | byte d = 0; 17 | for(int b=0; b < 8; b++) { 18 | int px = (x*8) + b; 19 | int pixel = (px >= 240) ? 0 : i.getRGB(px, y); 20 | d <<= 1; 21 | d |= (pixel & 1); 22 | } 23 | o.writeByte(~d); // 0 is off (white), 1 is on (black) so invert bits. 24 | } 25 | } 26 | 27 | o.flush(); 28 | o.close(); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /wikiwriter/Readme.md: -------------------------------------------------------------------------------- 1 | Wikiwriter 2 | ========== 3 | The Wikiwriter turns a Wikireader into a desktop writing prompt generator, capable of creating inspiring ideas for overall works, characters and settings. 4 | 5 | ![start screen](https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/master/wikiwriter/screenshots/writerstart.png) ![example story form](https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/master/wikiwriter/screenshots/writerexample.png) 6 | 7 | To generate random ideas, this application loads a series of text files with "chunks" and assembles them together much like a madlib. The `rtable` defining word handles this data loading process and tracks how many of each chunk type exists in the provided text files. The word `any` can then pick one of these elements and leave a Forth string on the stack. 8 | 9 | Random numbers are generated by a crude but sufficiently effective linear-congruential generator. The seed is written to the MicroSD card after every random number is picked, ensuring that if the device is powered off it will not repeat earlier selections. These constant writes to the MicroSD card may ultimately limit the lifespan of the device, but with casual use it shouldn't pose problems. 10 | 11 | This program makes use of several full-screen bitmaps. Rather than write a decoder for a complex image format like PNG or even BMP, I made a Java program (`ImageConverter.java`) which prepares monochrome images in any common format in the raw format used by the Wikireader's memory-mapped display. The word `blit-image` can then very easily load a file from disk directly into this framebuffer. The framebuffer is padded to 32 bytes per scanline, and this is taken into account by the utility. I was pleasantly surprised at the speed of this routine with no particular effort to optimize its performance- it may well be possible to use a modified form of this technique to produce smooth animation. 12 | -------------------------------------------------------------------------------- /wikiwriter/bootmenu.4th: -------------------------------------------------------------------------------- 1 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 2 | \ 3 | \ Inspire-o-tron 4 | \ 5 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 6 | 7 | decimal lcd-cls 8 | 9 | : inc dup @ 1+ swap ! ; ( addr -- ) 10 | : dec dup @ 1- swap ! ; ( addr -- ) 11 | 12 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 13 | \ 14 | \ Random number generator 15 | \ 16 | \ A simple linear congruential generator 17 | \ with a seed persisted to a file. 18 | \ 19 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 20 | 21 | variable seed 22 | 23 | : seed-file s" DATA/SEED.TXT" ; ( -- addr len ) 24 | 25 | : load-seed ( -- ) 26 | seed-file r/o open-file 0= if 27 | >r seed 1 cells r> dup >r read-file 2drop 28 | r> close-file drop 29 | else 30 | drop 8675309 seed ! 31 | then 32 | ; 33 | 34 | load-seed 35 | 36 | : save-seed ( -- ) 37 | seed-file delete-file drop 38 | seed-file w/o create-file 0= if 39 | >r seed 1 cells r> dup >r write-file drop 40 | r> close-file drop 41 | else 42 | drop 43 | then 44 | ; 45 | 46 | : random ( max -- n ) 47 | seed @ 1664525 * 1013904223 + dup seed ! over mod 48 | dup 0< if over + then nip 49 | save-seed 50 | ; 51 | 52 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 53 | \ 54 | \ Random tables 55 | \ 56 | \ `rtable` loads lines from a text file 57 | \ into memory, and then the `any` 58 | \ helper word can retrieve a random 59 | \ entry from this table as a string. 60 | \ 61 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 62 | 63 | 128 constant entry-size 64 | 65 | variable file-handle 66 | variable entry-count 67 | variable entry-head 68 | 69 | : rtable ( addr len -- ) 70 | r/o open-file 71 | create 72 | 0= if 73 | file-handle ! 74 | here entry-count ! 0 , 75 | 76 | begin 77 | here entry-head ! 0 , \ reserve str len slot 78 | entry-size allot \ reserve str storage 79 | 80 | entry-head @ 1 cells + \ storage addr 81 | entry-size \ storage size 82 | file-handle @ read-line 83 | drop 0= if 84 | drop \ discard bogus line data 85 | file-handle @ close-file drop \ close file handle 86 | exit 87 | then 88 | 89 | entry-head @ ! \ copy the length into place 90 | entry-count @ inc \ increment entry no. 91 | again 92 | else 93 | drop ." Unable to load rtable data." cr 94 | then 95 | ; 96 | 97 | : any ( rtable -- addr len ) 98 | dup @ random ( base random-index ) 99 | entry-size 1 cells + * ( base random-offset ) 100 | + 1 cells + ( entry-base ) 101 | dup 1 cells + swap @ 102 | ; 103 | 104 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 105 | \ 106 | \ Wrapped text display 107 | \ 108 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 109 | 110 | variable text-addr 111 | variable text-len 112 | variable word-addr 113 | variable word-len 114 | 115 | : lcd-column lcd-x @ font-width / ; ( -- n ) 116 | 117 | : next-word ( -- word-addr word-len ) 118 | text-addr @ word-addr ! 119 | 0 word-len ! 120 | begin 121 | \ if we've reached whitespace or eos, break. 122 | text-addr @ c@ 32 = text-len @ 1 < or if 123 | text-addr inc 124 | text-len dec 125 | word-addr @ 126 | word-len @ 127 | exit 128 | then 129 | text-addr inc 130 | text-len dec 131 | word-len inc 132 | again 133 | ; 134 | 135 | : text-wrap ( addr len -- ) 136 | text-len ! 137 | text-addr ! 138 | begin 139 | text-len @ 1 < if exit then 140 | next-word 141 | dup 1+ lcd-column + lcd-text-columns 1- > if lcd-cr then 142 | 8 0 lcd-move-rel 143 | lcd-type 144 | again 145 | ; 146 | 147 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 148 | \ 149 | \ Static data: 150 | \ 151 | \ the word s" works somewhat strangely 152 | \ on the wikireader; it doesn't appear 153 | \ to function as an immediate word. 154 | \ as a result, we have to resort to 155 | \ a slightly hacky workaround to 156 | \ provide filenames for our rtable 157 | \ declarations. 158 | \ 159 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 160 | 161 | : jobs s" DATA/JOBS.TXT" ; jobs rtable job 162 | : wants s" DATA/WANTS.TXT" ; wants rtable want 163 | : issues s" DATA/ISSUES.TXT" ; issues rtable issue 164 | 165 | : forms s" DATA/FORMS.TXT" ; forms rtable form 166 | : themes s" DATA/THEMES.TXT" ; themes rtable theme 167 | : features s" DATA/FEATURES.TXT" ; features rtable feature 168 | 169 | : descs s" DATA/DESC.TXT" ; descs rtable desc 170 | : locs s" DATA/LOCS.TXT" ; locs rtable loc 171 | : places s" DATA/PLACES.TXT" ; places rtable place 172 | 173 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 174 | \ 175 | \ Image blitting: 176 | \ 177 | \ Read a packed 1-bit bitmap 178 | \ directly into the framebuffer 179 | \ from a file. 180 | \ 181 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 182 | 183 | : blit-image ( addr len -- ) 184 | r/o open-file 0= if 185 | file-handle ! 186 | 187 | lcd-vram-size 0 do 188 | lcd-vram i + 32 file-handle @ read-file 189 | drop drop \ I don't care about the return value. 190 | 32 +loop 191 | 192 | file-handle @ close-file drop 193 | else 194 | drop ." Unable to load image data." cr 195 | then 196 | ; 197 | 198 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 199 | \ 200 | \ The main program: 201 | \ 202 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 203 | 204 | : draw-common ( addr len -- ) 205 | lcd-clear-all 206 | lcd-white 207 | 1 1 lcd-at-xy 208 | lcd-type 209 | lcd-black 210 | 1 3 lcd-at-xy 211 | ; 212 | 213 | : draw-who ( -- ) 214 | s" Character... " 215 | draw-common 216 | 217 | job any text-wrap 218 | s" who wants " text-wrap 219 | want any text-wrap 220 | s" but is impeded by " text-wrap 221 | issue any text-wrap 222 | ; 223 | 224 | : draw-what ( -- ) 225 | s" Writing prompt... " 226 | draw-common 227 | 228 | s" write " text-wrap 229 | form any text-wrap 230 | s" exploring " text-wrap 231 | theme any text-wrap 232 | s" and incorporating " text-wrap 233 | feature any text-wrap 234 | ; 235 | 236 | : draw-where ( -- ) 237 | s" Setting... " 238 | draw-common 239 | 240 | desc any text-wrap 241 | loc any text-wrap 242 | place any text-wrap 243 | ; 244 | 245 | : handle-buttons ( -- updated ) 246 | button case 247 | button-none of endof 248 | button-power of s" DATA/SPLASH1.IMG" blit-image endof 249 | button-left of draw-who endof 250 | button-centre of draw-what endof 251 | button-right of draw-where endof 252 | endcase 253 | ; 254 | 255 | : main ( -- ) 256 | ctp-flush 257 | key-flush 258 | button-flush 259 | s" DATA/SPLASH2.IMG" blit-image 260 | begin 261 | key? if key-flush then 262 | ctp-pos? if ctp-flush then 263 | button? if handle-buttons button-flush then 264 | wait-for-event 265 | again 266 | ; main 267 | -------------------------------------------------------------------------------- /wikiwriter/screenshots/writerexample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/wikiwriter/screenshots/writerexample.png -------------------------------------------------------------------------------- /wikiwriter/screenshots/writerstart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/Wikireader-Adventures/3e3ea0674b9fc5d29a8d66cd993c5d3ce69d3308/wikiwriter/screenshots/writerstart.png -------------------------------------------------------------------------------- /wikiwriter/wikiwriter.4th: -------------------------------------------------------------------------------- 1 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 2 | \ 3 | \ Wikiwriter 4 | \ 5 | \ A random writing prompt generator. 6 | \ 7 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 8 | 9 | decimal lcd-cls 10 | 11 | : inc dup @ 1+ swap ! ; ( addr -- ) 12 | : dec dup @ 1- swap ! ; ( addr -- ) 13 | 14 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 15 | \ 16 | \ Random number generator 17 | \ 18 | \ A simple linear congruential generator 19 | \ with a seed persisted to a file. 20 | \ 21 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 22 | 23 | variable seed 24 | 25 | : seed-file s" DATA/SEED.TXT" ; ( -- addr len ) 26 | 27 | : load-seed ( -- ) 28 | seed-file r/o open-file 0= if 29 | >r seed 1 cells r> dup >r read-file 2drop 30 | r> close-file drop 31 | else 32 | drop 8675309 seed ! 33 | then 34 | ; 35 | 36 | load-seed 37 | 38 | : save-seed ( -- ) 39 | seed-file delete-file drop 40 | seed-file w/o create-file 0= if 41 | >r seed 1 cells r> dup >r write-file drop 42 | r> close-file drop 43 | else 44 | drop 45 | then 46 | ; 47 | 48 | : random ( max -- n ) 49 | seed @ 1664525 * 1013904223 + dup seed ! over mod 50 | dup 0< if over + then nip 51 | save-seed 52 | ; 53 | 54 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 55 | \ 56 | \ Random tables 57 | \ 58 | \ `rtable` loads lines from a text file 59 | \ into memory, and then the `any` 60 | \ helper word can retrieve a random 61 | \ entry from this table as a string. 62 | \ 63 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 64 | 65 | 128 constant entry-size 66 | 67 | variable file-handle 68 | variable entry-count 69 | variable entry-head 70 | 71 | : rtable ( addr len -- ) 72 | r/o open-file 73 | create 74 | 0= if 75 | file-handle ! 76 | here entry-count ! 0 , 77 | 78 | begin 79 | here entry-head ! 0 , \ reserve str len slot 80 | entry-size allot \ reserve str storage 81 | 82 | entry-head @ 1 cells + \ storage addr 83 | entry-size \ storage size 84 | file-handle @ read-line 85 | drop 0= if 86 | drop \ discard bogus line data 87 | file-handle @ close-file drop \ close file handle 88 | exit 89 | then 90 | 91 | entry-head @ ! \ copy the length into place 92 | entry-count @ inc \ increment entry no. 93 | again 94 | else 95 | drop ." Unable to load rtable data." cr 96 | then 97 | ; 98 | 99 | : any ( rtable -- addr len ) 100 | dup @ random ( base random-index ) 101 | entry-size 1 cells + * ( base random-offset ) 102 | + 1 cells + ( entry-base ) 103 | dup 1 cells + swap @ 104 | ; 105 | 106 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 107 | \ 108 | \ Wrapped text display 109 | \ 110 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 111 | 112 | variable text-addr 113 | variable text-len 114 | variable word-addr 115 | variable word-len 116 | 117 | : lcd-column lcd-x @ font-width / ; ( -- n ) 118 | 119 | : next-word ( -- word-addr word-len ) 120 | text-addr @ word-addr ! 121 | 0 word-len ! 122 | begin 123 | \ if we've reached whitespace or eos, break. 124 | text-addr @ c@ 32 = text-len @ 1 < or if 125 | text-addr inc 126 | text-len dec 127 | word-addr @ 128 | word-len @ 129 | exit 130 | then 131 | text-addr inc 132 | text-len dec 133 | word-len inc 134 | again 135 | ; 136 | 137 | : text-wrap ( addr len -- ) 138 | text-len ! 139 | text-addr ! 140 | begin 141 | text-len @ 1 < if exit then 142 | next-word 143 | dup 1+ lcd-column + lcd-text-columns 1- > if lcd-cr then 144 | 8 0 lcd-move-rel 145 | lcd-type 146 | again 147 | ; 148 | 149 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 150 | \ 151 | \ Static data: 152 | \ 153 | \ the word s" works somewhat strangely 154 | \ on the wikireader; it doesn't appear 155 | \ to function as an immediate word. 156 | \ as a result, we have to resort to 157 | \ a slightly hacky workaround to 158 | \ provide filenames for our rtable 159 | \ declarations. 160 | \ 161 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 162 | 163 | : jobs s" DATA/JOBS.TXT" ; jobs rtable job 164 | : wants s" DATA/WANTS.TXT" ; wants rtable want 165 | : issues s" DATA/ISSUES.TXT" ; issues rtable issue 166 | 167 | : forms s" DATA/FORMS.TXT" ; forms rtable form 168 | : themes s" DATA/THEMES.TXT" ; themes rtable theme 169 | : features s" DATA/FEATURES.TXT" ; features rtable feature 170 | 171 | : descs s" DATA/DESC.TXT" ; descs rtable desc 172 | : locs s" DATA/LOCS.TXT" ; locs rtable loc 173 | : places s" DATA/PLACES.TXT" ; places rtable place 174 | 175 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 176 | \ 177 | \ Image blitting: 178 | \ 179 | \ Read a packed 1-bit bitmap 180 | \ directly into the framebuffer 181 | \ from a file. 182 | \ 183 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 184 | 185 | : blit-image ( addr len -- ) 186 | r/o open-file 0= if 187 | file-handle ! 188 | 189 | lcd-vram-size 0 do 190 | lcd-vram i + 32 file-handle @ read-file 191 | drop drop \ I don't care about the return value. 192 | 32 +loop 193 | 194 | file-handle @ close-file drop 195 | else 196 | drop ." Unable to load image data." cr 197 | then 198 | ; 199 | 200 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 201 | \ 202 | \ The main program: 203 | \ 204 | \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 205 | 206 | : draw-common ( addr len -- ) 207 | lcd-clear-all 208 | lcd-white 209 | 1 1 lcd-at-xy 210 | lcd-type 211 | lcd-black 212 | 1 3 lcd-at-xy 213 | ; 214 | 215 | : draw-who ( -- ) 216 | s" Character... " 217 | draw-common 218 | 219 | job any text-wrap 220 | s" who wants " text-wrap 221 | want any text-wrap 222 | s" but is impeded by " text-wrap 223 | issue any text-wrap 224 | ; 225 | 226 | : draw-what ( -- ) 227 | s" Writing prompt... " 228 | draw-common 229 | 230 | s" write " text-wrap 231 | form any text-wrap 232 | s" exploring " text-wrap 233 | theme any text-wrap 234 | s" and incorporating " text-wrap 235 | feature any text-wrap 236 | ; 237 | 238 | : draw-where ( -- ) 239 | s" Setting... " 240 | draw-common 241 | 242 | desc any text-wrap 243 | loc any text-wrap 244 | place any text-wrap 245 | ; 246 | 247 | : handle-buttons ( -- updated ) 248 | button case 249 | button-none of endof 250 | button-power of s" DATA/SPLASH1.IMG" blit-image endof 251 | button-left of draw-who endof 252 | button-centre of draw-what endof 253 | button-right of draw-where endof 254 | endcase 255 | ; 256 | 257 | : main ( -- ) 258 | ctp-flush 259 | key-flush 260 | button-flush 261 | s" DATA/SPLASH2.IMG" blit-image 262 | begin 263 | key? if key-flush then 264 | ctp-pos? if ctp-flush then 265 | button? if handle-buttons button-flush then 266 | wait-for-event 267 | again 268 | ; main 269 | --------------------------------------------------------------------------------