Log In  
[back to top]

Yep, I'm still working on my Sprite/Flag routine.

Yet I left one of my other items running in the background in a separate Pico-8 tab last night, awoke to see that it said:


Well the next morning I cleared the slate and started new code for it:

until forever

About 12-hours later it crashes and says:


Now I don't think there's any recursion involved in this, but if it's running out of memory just by doing a loop, it could be a problem for others coders, right ?

And yes, I know "forever" is a NIL statement.

Nonetheless for it to crash, thoughts ?

P#68336 2019-10-02 00:31 ( Edited 2019-10-02 01:14)

Cart #map2bbsimage-1 | 2019-09-28 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

To load this, in PICO-8 type:

load #map2bbsimage-1




This function will take coordinates from a cart of your choosing and let you specify from your MAPPER (x1,y1,x2,y2) where x1,y1 is top-left-hand corner of your map and x2,y2 is bottom-right-hand corner of your map to convert it to a BBS image that can be pasted in the forum.

It also clears the screen and shows you what was transferred so you can be certain you have the right image.

This is useful for collaborations on bigger projects and demos so you can share what you are working on in the mapper without having to use screen-capture, multiple pastes because it goes past the screen, or even lose sharpness or clarity because of a dithered resize.

Sample sprites and mapper data are included to get you started. Function is one-line so just copy that one-line to your project and run it from there.


P#68223 2019-09-28 14:31 ( Edited 2019-09-28 20:12)

Cart #as-0 | 2019-12-31 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
TO LOAD THIS CART in Pico-8 immediate mode, type:

load #as]

(12-31-19) Added youtube video comparison.

It's difficult to emulate some of the wondrous things that are done in arcade games. One of which I was especially fond of is when Galaxian first made the scene as a space shooter. It had tiny stars that were colored and they flickered perfectly.

Here now is one function to do just that for you. Include in any of your space shooters. Just add to _draw() or _update(). Fire and forget. You don't even need code to initialize the stars as this is also covered in my one function.

Compare with original:


P#68205 2019-09-28 01:02 ( Edited 2019-12-31 18:44)

Cart #str2board-0 | 2019-09-27 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This program may not be too useful for you Pico-8 veterans but may prove instrumental to those learning the system or want an easy route to build their own mapper.

Obviously you can use the MAPPER if you want, but if you don't want to or can't, you may find this code to be of interest.

Here is the top of the source to show you what is going on in it.

As you can see it is a single string, 240-characters in length that uses only the special characters for Pico-8. If you check out the sprites you have:

Where you can replace each letter of the alphabet here with your own custom image. Then in the source editor, press SHIFT followed by that letter to enter in that character for the string in your board.

Run the program to see the results and build your own original game around this.


P#68201 2019-09-27 22:03 ( Edited 2019-09-28 19:07)

Cart #vvm-6 | 2019-09-27 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

To load this cart, in Pico-8 immediate mode type:


UPDATE: 09-27-19

  • Sped up load/save to external file process considerably by using internal temporary storage.
  • Converted loose initialize to function.

  • Added "Skeleton" file to make it easier for others to use. Includes the only 3-functions you need to make it work, but for loading and saving. Found HERE:
    Cart #vvm_skel-0 | 2019-09-27 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
-- skeleton file
function _init()

function _update()

function _draw()

function initvar()
function var2file(filename)
function file2var(filename)

To load this cart, in Pico-8 immediate mode type:


UPDATE: 09-26-19
Added ability to recall all software changes to sprites,mapper,sounds, and music even if you change them via POKE() in your code. Before after you loaded or saved your VARS it would only reset to what you have default in your cart. Code is a little slower because of this but works fine. New temporary file "_" is created because of this - but data is not affected.

. . .

Back when PICO-8 first came out, it was announced that you could load and save externally 64-numbers per cart. And life was good.

Then someone realized that this is actually 256-bytes and wrote routines to directly access that memory. And life was better.

Another person took that and said that 256-bytes could be broken down to 2048-switches. 8 bits per byte. And that was an interesting find to say the least.

Now me ? I've always been interested in compression - ever since I created S2 those 20+ years ago and wrote in it, that's right, the same name but a different method, a Virtual Variable Minder to keep track of all of my player and companion attributes and inventory.

I've also been experimenting with memory storage and recall in Pico for years now. At one point I wrote code that let you save up to 4096-bytes of memory at the cost of half your sprite space. It was good but the disadvantage was that you could only have one-save file per cart. I know this could be improved upon if I worked at it.

So now that ZEP has finally fixed the memory problem I was experiencing in an earlier version of PICO, I am successful - and do have a good grasp of how to work with up to 12288 bytes of memory that be both loaded and saved to an external file and touches no sprites, no mapper, no sound, and no music memory. And you can have as many as you want. You will find how in the routines I wrote here.

Now it is only recently I have discovered the use and power of "Variable dot." That is, any variable followed by the period key. The real advantage is that you can set any variable with it and later recall all the variables that match the prefix with my DLLs (and that's what I'm calling these routines).

In this, I have written 2 useful functions. One of which will save all your vars to any filename you want. Works everywhere:

  • immediate mode
  • EXE export
  • run in Splore
  • run in Lexaloffle's BBS
  • offline HTML export

It truly does work everywhere. And you can still have any number of files no matter the port.

No need for messy arrays, pokes, or anything like that. I have done all this work for you. Here are some examples of variables that can be loaded and saved easily in one pass.

for i=0,15 do
var.equip[2]="bronze sword"
var.equip[41]="silver armor"
var.equip[836]="wooden shield"
var.equip[1531]="copper helmet"
var.equip[25493]="leather boots"

As you can see you can have quite non-standard variables as well. To save these call the function, VAR2FILE(filename). If you just want to view all the variables for debugging, choose the filename of "*" instead.

To load back your variables (and it doesn't need to be the same cart), call the function FILE2VAR(filename) where the filename is the same as the one you chose above.

And YES this does mean that you can indeed save multiple files since the filename can be anything at all and well exceed 65536 bytes of storage or even more.

There is one catch, I am using the "{" and "}" keys as markers for variable data storage and recall. Do not use these two-characters in any capacity for strings or string arrays. You do that and my program will work just fine.

I am also adopting a new stance. Years ago back in BlitzMAX DLLs were bandied about quite a bit. These were very popular often over standard released sourcecode in that you could "fire and forget" without ever having to worry about the actual source-code itself.

Therefore I am hanging up the cape of the dw817 laboratory. Instead it will be the dw817 Magic Shop. Good powerful routines but each in one magical line of code instead of 20-30 with massive remarks like I did earlier.

So too have I done that with these functions. They are each only one-line long and written about as small coding as is possible for me. You copy those two-lines plus the one line to initialize your "VAR." and you're DONE. No need for anything else - should work in any program and in any capacity.

Thanks especially to those who helped me understand dot variables and how to view them all via PAIRS(). I could not have done this without you !

Included now is a full cart demonstrating its ability to both load, view, and save. Notice when the variables are viewed for debugging that I have made use of { } in data separation.


P#68171 2019-09-27 00:45 ( Edited 2019-09-28 19:05)

[Under spam review]

P#68102 2019-09-24 15:46 ( Edited 2019-09-24 21:19)


Could someone help me with this please ? I'm trying to understand how this works.


for i in all(var) do
  print(i.." "..var)

And yes, I know I can use:


But I want to be able to iterate each item per line and in any order, and the ability to remove them as well.


And to recall a value: print(var."playhp") returns 500. And ability to recall a value be reference:

print([email protected]) also to return 500.

And print(#var) to return 4, currently returns 0 (zero).

Thanks in advance !

P#68005 2019-09-22 21:28 ( Edited 2019-09-22 23:01)

Cart #yield_fireball-0 | 2019-09-22 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

You ever have that moment when somebody tells you something and you SORT OF get it but not really, and then later, maybe a day or two you cry out, "Ah ha !" because then you understand it ?

Well I'm not going to claim full knowledge of the YIELD() command, but I will tell you what it CAN do - at least for me.

I can take any program I've written to date and make it OOPS very simply.

Replace all FLIP() with YIELD(), then make a coroutine to run my MAIN() function. Done.

But it goes beyond this. Since I can now join the ranks of _DRAW() and _UPDATE() this means I can write a custom background engine that operates exactly as I like it.

In this case for this example you can hit "Q" and bring up Quick Debugger which shows memory usage and how much of the CPU is being tasked. You can also hit [ESC] and type RESUME to leave off where you where.

Before YIELD() I couldn't do either of these things nor read the CPU. Now I can. This does herald the END of FLIP() for me and the very welcome arrival of YIELD().

What does this mean for you ? YIELD() does not just exit a function it retains the exact position when you return even if you were nested in a whirl of FOR/DO, IF/END, and REPEAT/UNTIL statements. It also retains all local variables and values at the point you exit and return. That is immensely powerful.

Giving credit where credit is due. I found out about YIELD() from freds72 HERE:

and MBoffin HERE:


. . .

More and more I begin to appreciate this Pico-8 system and daresay it is the most powerful programming language I have ever come across.

P#68002 2019-09-22 16:47 ( Edited 2019-09-22 21:36)

Cart #implosion-1 | 2019-09-21 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Years ago I had written a QBasic program for Gina in Taiwan. In it, it imploded the map of Texas along with a greeting. When you ran it, it had the pixels come from all sides of the screen to implode the image I put in there.

Now you can do the same thing in Pico-8 !

Create any picture you want, call initexplosion() then explosion(1,flag) Flag to 1 if you want to skip seeing the explosion and only want to calculate for it. Then you are ready. Now call explosion(-1,0) to see the neat implosion effect of the image you put in there.

P#67980 2019-09-21 21:22 ( Edited 2019-09-21 21:24)

I first off wanted to let you know that I was just experimenting recording some .GIFs in PICO when I noted that the last .GIF I made was 6.49mb in size.

I loaded this up in VirtualDUB to check each frame in it, to make sure it looked alright, and then tried saving it back as an EXPORT .GIF to compare filesizes.

The filesize THEN was only 209k ! A 97% reduction !

I compared both. None miss frames, none have any distortion. They are the same EXCEPT that VirtualDUB has some massive compression going on there !

So ... Zep, someone, anyone ? the .GIF saver in current PICO-8 can definitely be optimized. No doubt about it. VirtualDUB was written 19-years ago - so it's not something new.

I can't upload the 6.49mb GIF in comparison here, says the filesize is too big.

Here is the 209k GIF though so you can see it's not missing anything. There's definitely good compression going on there !

I guess the good news is I've introduced a program (VirtualDUB) that will let users now save .GIFs of their cart directly in the BBS that can exceed well into minutes as they are so small in filesize as they are 3% the size of their original - and have the ability to edit out frames they don't want included in the presentation .GIF.

VirtualDUB is 100% Freeware and you can find it HERE:



P#67977 2019-09-21 18:36 ( Edited 2019-09-21 21:36)

Cart #xor_flower-0 | 2019-09-19 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Years ago computers had very little memory. I am reminded of the Apple ][ computer which although having 2-HIRES graphic pages each 8192-bytes in size with a resolution of 280x192 B&W pixels, you only had about 16k of RAM space if you used both of them for your program.

The original method was to plot an image on one page while viewing the other, then swap the two so you were always plotting on one while viewing the other. Yet this technique cost two HIRES pages of memory.

So a new method was adopted to handle plotting sprites and graphics over existing static images, and that method was called XOR.

On the Apple for instance you could plot a shape with XOR dots, that is for every pre-existing black dot you plotted on, it would appear white. Likewise if you plotted on a previously existing white dot, the plotting color for your dot would be black.

To erase the shape you would repeat the drawing exactly which would also recover the background beneath it - and this method only required the use of one HIRES page instead of the need for two so you could program in an additional 8192-bytes of code for your program, critical to many video-games that many years ago.

XOR also does some interesting graphic effects. If you XPLOT a line and then plot ANOTHER XOR LINE almost exactly like it but at a slightly different angle you can an interesting kind of warped box effect or flower as you see here.

Now as you cannot XPLOT a LINE in Pico-8, I wrote a routine to do just that for you called PLINE using coordinate arguments the same as LINE()(x1,y1,x2,y2).

So this cart is twofold, not only do you get a lovely mathematical flower but you can use this small coded PLINE() routine for your own works to have one target chase another, perhaps for your opponent to fire a shot at you despite where they are on the screen, or even just to simply draw a line changing color mid-step as you go.

It's up to you !

P#67910 2019-09-19 23:26 ( Edited 2019-09-19 23:43)

Credit to MBoffin who inspired me to write this, mostly so I myself could prove that I understood seldom used Pico-8 command set of COROUTINES such as COCREATE(), CORESUME(), and YIELD().

Cart #cocreate_demo-0 | 2019-09-19 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

If you just want the source without the sound effects, that can be found HERE:

-- dw817's very simple
-- cocreate() program

function main() ------------->>




-- if press (x) or this is the
-- first time to run,
-- prepare for being able to
-- call function "act" as a
-- co-creation
if btnp(5) or init==0 then

-- make a pointer for the
-- cocreation function "act"
  sfx(0) -- low pitch

-- if press (o) then call
-- routine here to plot three
-- circles, one at a time, and
-- one for each press
if btnp(4) then

-- update screen

until forever
end --<<-----------------------

-- three circles, click (o)
-- three times to see all three
function act()
  sfx(1) -- high pitch

-- each time yield is used,
-- the position of where the
-- program is in the function
-- is recorded and the function
-- exits

-- the second time you press
-- (o) the function will start
-- here, not at the beginning
  sfx(1) -- high pitch

-- as above, this function
-- starts here on a 3rd press
  sfx(1) -- high pitch

-- there is nothing more here
-- so pressing (o) a 4th or
-- more does nothing.
-- you must call cocreate()
-- again in order to reset
-- this function to start
-- running the 3-circles again



P#67882 2019-09-19 01:51 ( Edited 2019-09-19 02:12)

My Father died nearly 20-years ago from today. Outside of my Sister and my Step-Mom, they are the only family I have now.

I remember my Step-Mom sending me the classic poem from Robert Frost.

And I remembered ... I remember when I was young.


So ... in tribute, I have two programs. One is to try and recreate that very program for the TRS-80 I typed in those so many years ago - and to have it run at the same speed.

Cart #siparefiti-0 | 2019-09-17 | Code ▽ | Embed ▽ | No License

The other is something a bit more magical. A year after the funeral I wanted to make SNOW, real snow, on the computer, and as accurately as I could. A majestic tribute to my Dad and that program typed in from so many years ago.

So I watched the movie, "Dr. Zhivago" and watched very carefully the snowflakes in them. One frame at a time. For many long days I studied their movements - and wrote down in my notes what I saw and what I observed.

[1] Few videogames to date apparently really follow the accurate movement of snowflakes.
[2] Some fall as fast as raindrops, big ones I believe.
[3] They do fall a bit slow and fast, based I think upon their shape.
[3] They are very light and airy and a slight wind will completely alter their course.

And today, I have what I believe is quite accurate for movement in snowflakes. And I had it available for GWBASIC in my S2 project, I had it for BlitzMAX, and now it is available - to you - for Pico-8, changing the math slightly to accommodate the larger pixels.

Please enjoy ...

Cart #noyidotono-0 | 2019-09-17 | Code ▽ | Embed ▽ | No License

P#67782 2019-09-17 01:07 ( Edited 2019-09-17 01:22)

I have never really liked to write code in BlitzMAX despite the fact it can work with a screen of 1980x1080 with true 64-million color pixels for a very simple reason. It takes time to compile the code and test it.

About 5-seconds to be precise, and that includes finding errors, even for a 2-line program.

My programming style if you are curious is a little like a rabid rabbit. It's like I take a cracker, nibble on it, look at it, nibble on it, look at it again, and nibble a little bit more.

That is - I write a bit of code, run it, add a bit more, run it again, then add a bit more.

My Dad was the opposite in that he could sit down and write a flawless program from beginning to end and NEVER have to run it once until he knew it was completely done. I can't do that.

So ... Pico-8 is a bit of my friend now for as you know when you RUN or press CTRL+R the language is already off like a shot and running.

Therefore I decided I could use it to write my Pico-8 website of favorite games.

And indeed I did.


All I'm doing is taking my text data file of:

# of stars
author's name
name of cart
description of cart
Actual cart ID name
Website where cart appears

Have a blank line separate, and then give the data for my next favorite cart if there is one, run my program, and the HTML to show what you saw above is saved and written.

So I wrote a program in PICO to read that text data and create a HTML file that has a neat and ordered table appear with the graphic cartridge and if you hover over any of them, you will get the number of stars, name, description, and author.

I even wrote it so it sorts all the data from highest number of stars to then on down so I don't have to do it myself manually. I could make it alphabetically sorted if someone feels slighted. :)

Here then is the program:

Cart #muzikufawu-0 | 2019-09-16 | Code ▽ | Embed ▽ | No License

Naturally it will not work in the BBS and is expecting a text file called, "list.txt" which has data as I described above. You need to LOAD this in immediate mode in PICO as follows:

load #muzikufawu

Here is a sample of the data to see what it is reading when it writes back, "web.htm"


Alfonzo's Bowling Challenge
Not your average bowling game.

Jack Of Spades
Turn-based RPG using playing cards.


You must have your data appear exactly like this. "list=[[" two open brackets, blank line, the cart info, another blank line, and two ending "]]"

Once your TEXT data is complete, save it.
Bring up NOTEPAD++ if you don't already have it open.

Open that TEXT data in there if you haven't yet done so.
Select from the menu, View, Show Symbol, Show All Characters.

If you see CRLF inverted then select from the menu, Edit, EOL Conversion, UNIX/OSX Format.

Then you should see only LF inverted which is the correct carriage return for PICO-8. CTRL+S to save.

Now, run my program. You can set DEBUG=1 to see each and every cart as it is processed. DEBUG=0 will just blur through everything and compile it quickly.

In your filer, delete "web.htm" if it exists. Rename "web.htm.p8l" to "web.htm"

Open "web.htm" in Notepad++ if you haven't yet done so. If you have and it's different from what the engine just created, you'll get a notice that the file has been modified and would you like to reload it ? Select YES.

Check the appearance. If the title's first character appears like this, ⭐150â then in the menu select, Encoding, Encode In UTF-8 Without Bom.

Then all the special characters will change to their designated icons. ⭐ and 🎮

Bring up your free website. If you can't think of any may I suggest TUMBLR ... or do you know of a good free site to build your website in ? Tumblr is 100% free and allows true HTML paste - which is what we need here.

In your "web.htm" tab in Notepad++ press CTRL+A to select everything there. Then CTRL+C to copy it to the clipboard.

Then in your internet browser in the area where you can type raw HTML for your custom website, press CTRL+V to paste the contents of web.htm directly there.

Save it, view it, enjoy it. :)

Please let me know if you do decide to use my code to build your own website or to assist you in this endeavor, I'd be curious to see it !

Once again, comments, questions, or kerosene. Let me know what you think !

P#67770 2019-09-16 20:30 ( Edited 2019-09-17 01:30)

The more I've been experimenting with the #INCLUDE command, the more I'm realizing that when you compile to an executable that - well ... you're not.

You can test this quite easily by using my homebrew Pico-8 compiler.

It's very simple.

-- external p8 compiler
-- written by dw817

-- note: you must compile this
-- program to exe in order to
-- use it

until forever

First, type out this code in the P8 source-code editor. Don't add anything else.
Save it. Run it. Press F7 for a screenshot even though nothing is there.

Now remove those 3-lines of repeat, flip, and until forever.

Go to sprites, mapper, sound, add stuff if you want. You don't have to.

When you're done with that, return to the sourcecode and add just below cls() the line:

#include source.txt

Now save this to a filename as a normal .P8 first. You'll get a warning that "could not #include file: source.txt". But don't worry about that. It worked. Then export as an EXE.

export engine.bin

Now with your normal filer, go inside the directory with the EXE, bring up NOTEPAD++

If you don't know what this is, you should get it. It is quite possibly the most powerful text editor on the planet, and it's 100% free.


Right, now start typing the source-code you want to have. Could be your own program. If you want sprites, mapper, or sound, you need to have created that above before you compiled to EXE.

Here is a sample program to test:

for i=0,127 do
  for j=0,127 do
  end--next j
end--next i
until forever

Now in NOTEPAD++ make sure you are saving LF only, not CRLF or CR which cannot be read in Pico-8.

To do so, click in the menu, Edit, EOL Conversion, and UNIX/OSX Format.

To ensure this is the case, from the menu, click, View, Show Symbol, Show All Characters.

Your custom program should now show an inverted LF to represent carriage-returns.

Save it as the filename, "source.txt" Make sure it is saved right where the EXE is located.

Now, you've saved your source-code which could be anything at all. It's time to test it.

Run the executable.

You will see your program run.

This points out something rather important. When you compile to an EXE it is apparently including the entire P8 system instead of creating an EXE that truly does bind your exact source-code to an actual original executable. otherwise it wouldn't know how to interpret the source text you just gave it. And it does.

Now this is not unknown behavior. Other languages I've programmed in such as Delphi Noetic F-Basic for the Commodore Amiga and GFA-Basic for Windows 3.1 all do this.

GFA was clever to create really tiny executables that worked so long as you had on path the main 3-megabyte DLL runtime library.

And we've seen this in countless interpretive programming languages. Both Integer and Floating Point Basic for the Apple ][ and GWBasic and Q-Basic for DOS.

So the real question now is, is this a security breach ? Possibly. Someone could indeed compile to an executable a blank program like I wrote above and then use an editor like NOTEPAD++ to post to SOURCE.TXT and run the executable each time to see their Pico-8 work executed.

Obviously this does not include the slick sprite, map, sound, and music editor. But it DOES work to compile any source-code at all.

Comments, questions, or kerosene ?

P#67671 2019-09-14 16:35 ( Edited 2019-09-14 17:24)

Zep, your front page HERE:


When I click on any of the games, the middle screen stays dark and does not load any game as intended.

I'm using Windows 10, 64-bit, Firefox Quantum v69.0.

If it doesn't work here chances are it doesn't work there for someone else. Thought I'd let you know ...

. . .

Solved. Just needed to clean the internet cookies for Firefox. Runs well here now.

P#67640 2019-09-14 00:26 ( Edited 2019-09-14 15:45)


Now that I've learned where the files are located, I've started to put together a little engine for myself that can create a nice list of Pico-8 games.

Here is what I've done so far:

sorry, had to shift some things around.

Hover over the cart to get a brief description and list the author.

Unlike embedding once you click the game it goes straight to the post in Lexaloffle where the game was released so not only can you play the game but read the author's comments, comments and questions from others, if you're logged in get a chance to add your own comments.

Special thanks to kittenm4ster and BoneVolt for their excellent programming and carts in the current list.

If it all looks okay, feel free to reply and post your game information and I'll add it to the list.

All I need is the URL address of where your game is (in Lexaloffle), it will look like this:
http: // www . lexaloffle.com / bbs / ?tid=00000

That and a brief game description of your game if it's not already included on the page, and that'll do it ! I can code the rest and feed it into my database.

If you're curious (not now but later) the list will be sorted by highest number of stars and go on down from there.

Or would you prefer they appear in the list on a first-come first-serve basis as they are now ?

Here is my table so far:

Alfonzo's Bowling Challenge
Not your average bowling game.

Jack Of Spades
Turn-based RPG using playing cards.

The Dead Should Die
A demake of the ghostly children in Little Nightmares, The Depths.

Not A Creature Was Stirring
(...Except Squeaky Whiskerson and his Marvelous Musical Mice!)

If I can remember I'll try to inject the list in every evening so you should always have an update and new cart every morning when you go to the game page.

. . .
Going to add the ability to sort the list by stars. I'll even post the code that is doing all of this once done. That's right, a Pico-8 program builds the HTML website !

P#67638 2019-09-13 23:54 ( Edited 2019-09-16 03:10)

Hello. As you know I've been recently experimenting with the new #INCLUDE command.

I have now recently found that if you use PRINTH it APPENDS text to a file, it does not overwrite it. If there is some way to overwrite the data, then this program could be run more than just a few times.


You can indeed load a text file as data for PICO-8. Modify it. Save it back. Then re-run the program to see all the changes recorded without having to save anything to SRAM or 256-byte storage.

One problem I ran into is that #INCLUDE can also not be used in a comparison. For instance, this:

IF 1==0 THEN

Will crash because it ignores any commands around it and WILL INCLUDE that data if it exists and crash if not.

Here is the program. It does work a few times. Can you make it so it's perfect and can be run over and over again ?

-- test load and save text file
-- by dw817

game_x={} game_y={} game_r={}

#include gamedata.p8l


for i=0,15 do

print"left for new name"
print"right to clear name"
print"up to clear circles"
print"down to create new circles"
print"press 🅾️ to save"


if btnp(⬅️) then
  for i=1,3 do
  end--next i
elseif btnp(➡️) then
elseif btnp(⬆️) then
  for i=0,15 do
    game_x={} game_y={}
    game_r={} game_c={}
elseif btnp(⬇️) then
  for i=0,15 do
elseif btnp(🅾️) then
  t='game_name="'..game_name..'" '
  for i=1,4 do
    for j=0,15 do
      if (i==1) v=game_x[j]
      if (i==2) v=game_y[j]
      if (i==3) v=game_r[j]
      if (i==4) v=game_c[j]
      if v!=nil then
        if j<15 then
    end--next j
    t=t.." "
  end--next i

until forever

NOTE, you WILL need to initially create a blank text file called, "gamedata.p8l" where you normally store your carts (notice that is an L on the end).

Then you must SAVE this program, any name, but must be in the same directory you just saved that data file in.

After this though it will work, about 3 times, then crash.

There needs to be some way of overwriting the "gamedata.p8l" instead of just appending data to it.

Once perfected this will be a remarkable and incredible way of loading and saving data bypassing the SRAM completely, and likely a lot more data could be loaded and saved this way, and a lot less coding to be involved since it's just source-code inclusion, modification, and saving. True self-modifying code.

But at this point I am truly stuck and not sure how to continue ...

P#67633 2019-09-13 20:40 ( Edited 2019-09-13 20:52)

There are not too many string-handling libraries I have come across in Pico-8. And for visual text this is not too surprising considering the small-size of the screen. :)

However, the point of this cart is to demonstrate a few things. One of which is that it is indeed possible to load a text ".txt" file inside your program. Now unfortunately the TXT file's contents cannot be changed once loaded. Like if you made a loop to view the contents each time.

But this does free you to use any other editor like NOTEPAD to prepare text data inside it.

For instance, you will need this. Highlight all of it, press CTRL-C. Bring up NOTEPAD. Press CTRL-V. Then save it on your HD as YUKON.TXT in a place you normally save your PICO-8 carts.


Day had broken cold and grey, exceedingly cold and grey, when the man turned aside from the main Yukon trail.
It was a steep bank, and he paused for breath at the top, excusing the act to himself by looking at his watch.
It was nine o'clock.
There was no sun nor hint of sun, though there was not a cloud in the sky.
It was a clear day, and yet there seemed an intangible pall over the face of things, a subtle gloom.
This fact did not worry the man.
He was used to the lack of sun.
It had been days since he had seen the sun, and he knew that a few more days must pass before that cheerful orb.
The man flung a look back along the way he had come.
The Yukon lay a mile wide and hidden under three feet of ice.


Notice it has correct uppercase and lowercase letters. If you want to make your own text file to use the libraries in this cart be certain to make your TXT file exactly the same way. With a variable "=" "[[" a skipped line, the data, another skipped line, and "]]" to finish followed by a carriage-return.

Cart #textlib-1 | 2019-09-12 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Alright, now load up this cart direct in PICO-8's editor.

load #textlib-1

The reason is this cart will NOT run either in Lexaloffle BBS or even compiled as an EXE - unless you have the TXT file alongside the EXE. And that could be a problem that needs to be resolved by ZEP. In any case, this =WILL= work in the editor once again provided you have the TXT file separate.

Now once you have the cart loaded, change to the directory where your TXT file is and SAVE your program right then in the same directory. Any name will do, but it must be saved in the same directory as the TXT file so PICO will know where to find it.

You will receive a warning that, "COULD NOT #INCLUDE FILE: YUKON.TXT" even though it's right there, but the file will have saved properly.

NOW IT WILL RUN. Run the cart.

Notice I am using a new function called PRINTS(). The reason is PICO-8 messes up the display if you use PRINT for any string that has \10 (CR) in it, and PICO-8 also has no internal word-wrap for strings. You must instead print out each character manually and handle CRs through code.

The advantage here also is now you can change the TXT file anytime you want and the results are immediately seen in your cart without the need to save it each time.

And that's it ! If you have any questions or difficulties, please let me know.

I hope you find this library useful for all of your import and string-handling needs.

P#67593 2019-09-12 18:23 ( Edited 2019-09-12 18:39)


Was thinking of some things I'd like to see in future PICO. Reiterating the post as quite a bit has changed since its initial writing.

Some of these suggestions are possible, others are not. What are some of your suggestions that you think would be acceptable for the next update in Pico-8 ?

Going to start latest suggestions as replies to this thread as this one post has gotten rather large.

Here we go ! First off, 2 errors:

!! Fix parenthesis error. This gives error: IF (K=="(") X=X-1 ... gives error because parenthesis is character to check.

!! Fix error with modulos when using high negative numbers. ?-32767%10000 yields 7233, incorrect.

added 10-14-19 some carts Some carts use the keyboard reader and disable P so it's impossible to exit if you brought it up in SPLORE. Suggest you add additional keystroke of CTRL+P and/or CTRL+C to exit cart if run from Splore.

this may not be a good idea, I don't know. Consider removing number "type" entirely in favor of all variables being treated as strings. Naturally if math is to be considered, then they can be used as such. The advantage would be since strings essentially can be any size then numbers far exceeding 32767 would be possible, both to the left and right of the decimal point.

In splore, add folder that shows last carts played in order of time they are left up. The cart that is played the longest always appears at the top.So if the console shuts down accidentally, they can find the last game they played via this extra list.

added 10-11-19 undo is a little twitchy. Suggest that if a whole line is undone it does not immediately jump to the last line edited but stays with the current repaired line first - either that or when CTRL-Z is pressed, delete only 1-character at a time.

Suggest options turn on/off for particular cart to treat NIL as error. That is, if you said, A=B and b=nil it would crash in an error. Also suggest opposite, if string tries to equal nil you would get "" if number variables tries to equal nil you would get 0, so no error would ever happen with nil, and once again this would be optional.[/color]

Use "#" for hex and "$" for binary thus a=#b a would then contain a string of the hex value of b. a=!b a would then contain a string of the binary value of b. Sub is also accepted. a=#b(1) would mean that a contains the left-most character of the hex value of b. a=#b(2,4) would mean that a contains the 2nd and 4th characters of hex value of b.[/color]

Use ! as logical NOT. a=true a=!a a now contains false.

Add new option to PRINT, SPR, SSPR, RECT, LINE, CIRC, RECTFILL, and CIRCFILL. Maybe just use ROT() command. Rotate the next thing drawn at an angle ROT(a,b,c) where a is the angle and b is the focus. if b and c are not used, it rotates in the center of the drawing element. If not, then it just an arbitrary location based on B and C.

Have function to determine if a point is within other points, rectangle, hexagon, octagon, etc. isinarea[a] where is a 2-dimensional a[][] array that contains numbers of each point to the object in question.

added 10-07-19 some older languages made use of error catching and the ability to make use of ERR and ERL where ERR was the error message and ERL was the error line number where it occurred. Error catching is important in carts that might try to do math with a NIL value.

added 10-06-19 good suggestion by Xii to add ability to merge frame-drawing. That is, you can draw one frame and then draw another frame over it changing it from 60fps to 30fps but with the added benefit that both fields are blended, including colors. Thus, WHITE pixels on one page and black on the other yield GRAY final pixel result. Affects visual only. Reading the pixel back gives black were that the last color plotted.

added 09-28-19 add record array ability to graphic elements thus. points={circ(50,50,50)} so array points[] will now contain a 2D array that has every single point made in the drawing circle starting from the top. Same with spr(), sspr(), rect(), rectfill(), circfill(), line(), and even print(). And of course the element is not actually drawn at all.

added 09-27-19 add high speed distance formula, uses one integer and 2-arrays, a, b[], and c[]. A is return value. B and C are 2-dimensional array comprised of numbered items. Calling A=CLOSEST(B,C,D) the return value is the single number stored in that 2-dimensional array that is closest to index from a.


Here you can see in the example that there are 6 points. Let's label them:

objx=[] objy=[]
objx[0]=2 objy[0]=0
objx[1]=5 objy[1]=1
objx[2]=1 objy[2]=2
objx[3]=3 objy[3]=4
objx[4]=2 objy[4]=5
objx[5]=6 objy[5]=5

So we are checking to see which object is closest to #4


the return value will be 3 as this object is closest to it. Could also write FARTHEST() function.

In the sprite editor have CTRL = and SHIFT CTRL = turn on selection and expand it by one character in that direction.

In the map editor, show what flags are lit (the 8 colored buttons) when cursor is atop a sprite tile.

Option in Sprite Editor to not just use 8-colors for sprite-flags but ability to enter 3- or 4-character text as a unique flag. This will definitely expand the ability of recognizing unique sprites that go beyond the standard 8 flag definitions.

added 09-26-19 add char { to read only first character of variable. {"hello"="h" {false="f" {23="2" } is opposite and reads last single character

add spread() command. IE: spread(cards,52) will create an array called cards and starting with index 1 will give them a value from 1-52. a negative number will reverse the order (cards,-52), 1st index is 52.

ability to run maximum speed. that is remove all stops and run code as fast as possible where it still pauses via update() draw() flip() or yield()

give every command defaults. For instance pset() with no arguments will plot color 6 in center of screen. give defaults to every single command.

Add to PRINT ability to center text, that is, by giving the x-value a string such as "c" a flag it will automatically calculate for the center of the screen based upon the string entered. An advantage will be a string that has one or more \10 in it. It will determine the single longest line and center accordingly. Also can have "r" for right-justification.

Add new command DEBUG(pos,color,test). This will plot 1-height 8-across pixeled bars at the bottom of the screen in user chosen colors and based upon events. IE: debug(0,8,"a>0") every draw() or update() cycle will draw a red line from pixel 0 to 7 if a>0. If not, it will plot BLACK. It accounts for local variables as well as global. Can have 16 in all.

Add two new commands, varload(vars,filename) and varsave(vars,filename). The argument is: varsave("test",filename) will save off every single variable and array that starts with those 4-letters "test." If argument is "" or nil then saves off EVERY single variable that contains a value, varload() will load them back again. if filename is blank and using varsave() then it saves off to a temporary memory, if varload() with no filename will load back from that temporary memory location. No limits. Can and will save and load EVERY SINGLE variable used in a cart.

Add two new commands, bound() and wrap(). Bound does exactly what MID() does. Wrap will take a number and wrap it around IE: x=wrap(1,126) if x=0 then x will now equal 126, if x=128 then x will now equal 3. Checks for big wrap-arounds too, x=4932 and then x=wrap(1,126) it will still work and give correct results.

Add option to load/save state. This can be controlled both by the player and in the source-code. SAVESTATE(n) where n is a value from 0-9. Save with SAVESTATE(n). Literally makes a snapshot of the entire PICO system, screen and all, and saves it to temporary memory location 0-9. LOADSTATE(n) recovers state - absolutely everything EXCEPT the line number the program is running at. If no argument is chosen, 0 is selected. During execution of cart, press F2 to save state, F3 to select a state number or import/export/delete, and F4 to load state. State data is saved via users/appdata() so it is always available until removed via F3.

Option for split-screen debugging. That is the upper portion of the screen is output and lower portion is debug. In debug mode the command running is highlighted. Standard keys apple. F8 to do this command/function but stay in this local or function. F9 to enter this command/function leaving this one behind. F10 to terminate debug and stop program here returning to command mode. All during this time the coder can also enter new values for variables to see how the program reacts to it.

Turn off mouse-cursor in editor when typing. Turn it back on when physical mouse is moved or clicked. Macintosh does this by default.

Fold functions, that is, you can press F9 or F10 when on a FUNCTION() line and it will close up only showing ">" at the front to show the contents are hidden. It still leaves any lines above or below the function visible including the single FUNCTION() line itself.

Add command scramble() usage: scramble(array,key). This will randomly rearrange each of the items in the array based upon the seed of key. To scramble, use positive number key. To unscramble use negative same number key. Use 0 to choose a random number that cannot be unscrambled later, IE: scramble(cards,0). Array cards() will now have each of its items rearranged randomly.

added 09-23-19 option for two new variable types. One can have value from 0-65535 (16-bits) the other can have value from -2147483648 to 2147483647 (32-bits). If this is possible, it should also be possible to have high floating. 1E+38.

Currently CTRL+number keys (0-9) currently do nothing in editor. Suggest they jump to tabs if tabs are set in sourcecode.

Right-clicking the mouse with FILL mode in sprite editor currently just fills, same as left click. Suggest it eyedrop the color as it does in normal pen mode.

Add option to press CTRL-C during cart execution to not only stop program but jump the editor to the exact source-line where it was halted. Resume from here is available if desired.

Add new command POLYGON(), POLYGONFILL. Usage: polygon(arrayof2dpoints,color). Also OVAL(), OVALFILL(). Usage: oval(x,y,radii-x,radii-y,color).

Clear all Sprite Flags for single sprite with SHIFT-CTRL-C or some other such non-used key combination.

Change pen size with hot keys like CTRL - CTRL +. Also change edit size via CTRL , "<" smaller and CTRL "." larger. So by default you edit 8x8, press CTRL "." and then you are editing 16x16. Add CTRL "[" to decrease whole sprite page and ctrl "]" to increase whole sprite page. CTRL+P for PEN, CTRL+F for fill. Holding down left mouse button over a pixel for a short time enters selection mode. Once mouse button is released, returns to PEN mode.

added 09-22-19 option for circ() and circfill() to have arc, add argument of angle 0 to 1 or 0 to 359. IE: circ(x,y,size,color,start-angle,end-angle)

Option for rect() and rectfill() to have rounded corners, can specify depth. IE: rect(x,y,x2,y2,color,roundness intensity)


You can run LUA on the PSP-1000 models and higher. It should be possible to run PICO-8 as well.

There is a program to convert HTML to Android APK. It should be possible to run Pico-8 as well.

C++ can use variable++ to increase by one or variable-- to decrease by one. Suggest future PICO have this ability.

KEYCONFIG can only be used in immediate mode. If you try to run it in a cart, it only executes it when the program exits, this means of course you cannot use it at all for an EXE. Suggest copying over current key configuration to exports or allow KEYCONFIG inside someone's sourcecode.

Have ability to import or export graphic sections, not just all 256-sprites in one set.

[color=$ff0040]Have ability[/color] to change repeat speed for BUTNP(). Currently it's a tad slow. Likely others would want to change the initial delay for the first repeat and the repeat speed after. If it can be changed via source-code so much the better. setbutnp(1stkeydelay,repeatdelay)

This is pretty high-tech but would be nice to have. Once GIF is calculated via record video, maybe have a simple editor come up where you can delete individual frames (like where you are typing RUN) in the GIF before it is fully saved. I'm doing this in VirtualDUB currently, I think it could be done in PICO.

added 09-21-19 Option to turn off not just all sound but optional MUSIC() and/or sound effects. Some music is very good and some sound effects are very good, sometimes - not all at the same time. :) So there would be =2= menu options instead of just 1.

Also it has been proven through VirtualDUB that the animated GIFs you are saving via VIDEO in PICO-8 can indeed be compressed up to 97% the current size that you have. Might be worth investigating.


Currently hitting BACKSPACE goes back a webpage even if the focus is on the P8 cart in the BBS. Hitting the TAB key also selects from the browser. This makes a text entry mode difficult. Suggest that all non-vital keys be locked and available in the cart until focus is lost. Also turn OFF all audio when clicked outside CART would be good too - or better yet just FREEZE the whole cart until it's frame is clicked again. Whereupon it continues both with sound and position - exactly where you left it.

Right-mouse-click in the sourcecode editor currently does nothing. Suggest a menu may appear. Search, Search and replace, Undo, Redo, Copy, Paste, Erase, etc.

Add a new argument to PRINT after color. Use 8-bits for each of 1 2 3 4 * 6 7 8 9 to draw outline around text. IE:

for if only the 8th bit is set:

for if bits 2, 4, 5, and 7 are set:

for if all 8 bits are set:

for if value is -1:

(it creates a full rectangle despite the character's image)

If it is -1 instead draw solid rectangle around text (1-pixel around edges, rectfill()). Default to color black. If additional argument chosen, that is the outline color. This also applies to sprites spr() and sspr() so sprites can also have an automatic and colored outline.

PLEASE add a grid for the sprite editor ! Or at least make it optional - easier for others to work exact pixels in the 8x8 or 16x16 area. You already have SPACEBAR in map editor show grid, can do same for sprite editor, but make it toggle ON/OFF so spacebar need not be held all the time.

NOTICED that when you export to .BIN that it uses the default keys despite me remapping the arrow keys to the number keypad. Should be able to export using user selections - or add key configure in menu (only for exports).

added 09-20-19 allow color 16 or 255 to be BXOR. That is, 15 is automatically subtracted from the color beneath the plotter thus. PSET(X,Y,16) will plot color 15 if 0 is beneath and 0 if 15 is beneath. PSET(X,Y,15-PGET(X,Y)). Same with RECT() RECTFILL() CIRC() CIRCFILL() LINE().[/color]

Also, create new command, n=BUTNW(). It will pause execution and wait for any standard joystick keypress. N will then contain a value from 0-5. If you call it without a variable in front, it will just wait for any joystick keypress but not return a value. If you enclose a value in the argument BUTNW(n) then it will wait until that very button is pressed.

A few suggestions. These should all be achievable in the current version of PICO-8.

Add 128 to colors to plot with new color and to change that palette # to use the extended if it is >=128.
PLOT(X,Y,C) rect() rectfill() line() color() print()
if C>=128 then not only does it plot the new color but directly modifies the palette for that single color index (0-15) to reflect this. Add extra argument to rect() rectfill() and line() so can plot outline around color, use 8-bit as listed above for PRINT(), also specify outline color or black by default.

pal() can now access new palette additionally. pal(original color,new color (>=128 possible),normal flag)

Create 4 new commands that do the exact same thing END does.
To help make code more readable. Obviously you could use these out of order, say ENDIF for a FOR/DO statement, but the point is to clarify readability for programmers. NEXT can have anything after it, it is ignored. Useful so you could have NEXT followed by the variable name in the FOR/DO statement.

Allow usage of number keypad arrow keys same as arrow keys in source code editor. Same with DEL and ENTER keys. Currently these are all disabled in the editor.

Every time you run your program it auto-saves your program as either the name you gave it or a default "backup" name to a backup directory.

Have an option (click-switch) to view source-code with tabs as normal or to view them as if they weren't there (source is all on one page).

Allow clipboard to be read and written to when running directly from lexaoffle. Currently it is prohibited.

Reading and writing to clipboard could be a way to save complex work as 7-bit encoded text including complex game progress passwords and custom data work if it's a type of miniature game-maker. If you're concerned about security, only permit 7-bit reading and writing of clipboard, characters #32-#126 only.

If that's not enough, limit the selection to up to 256-characters.

Never use print a value using black ink on a black background when in immediate mode typing out 'print(a)' or whatever. Instead default to color 6 if color 0 is found to be printing color. This could be configurable if someone really does want black ink on a black background by default.

Option to read off edge of screen as -1 instead of 0 (zero).
Option to read off sprite edge as -1 instead of 0 (zero).
Option to read off map edge as -1 instead of 0 (zero).

Option to read TRUE and FALSE as -1 and 0 (zero). This would help complex logic statements that involve math. I'm not the only one requesting this.

Have Fill pattern to a character not just for cross-hatch characters but ALL special icons including arrows, circle, X, etc.

Option to base all arrays starting with zero instead of forcing it via: count={[0]=0,1,2,3}

Option for PRINT with two arguments, the 2nd argument is now not X but color. New color applies if >=128

Add command to play pitch and duration bypassing need to create sound effects via table. Most early programming languages have this. SOUND(pitch,durat,type,flag) flag if TRUE means it will wait to play the full sound before continuing to run the rest of the code. ESC will always abort sound and program early. Type is instrument type. 6 being noise. If any arguments are missing, including first, defaults will be chosen. SOUND() defaults pitch, durat, type, and flag to default values.

Option to print normal text as reverse-case so if you import the string "Hello" it does not come out "hELLO" but instead correctly "Hello."

. . .


WAIT(a,b) ... wait value of 1 means to wait 1/1000th of a second. 1000 means to wait one second. If b is TRUE then also does screen update.

INPUT will allow someone to enter normal input, string only, integer only, or real value
I.E.: INPUTS(name) ... will bring up an input with optional keyboard (if Android) and let someone type in their name, accepted with CR or even spoken through microphone for cellphone, etc.

Using $ in a variable name forces it to be a string. No need for TOSTR()
Using % in a variable name forces it to be integer. No need for FLR() or CEIL()
Using # in a variable name forces it to be real. No need for TONUM()

Add new command. RAND. Rand (15) yields random integer number from 0-14. RAND(1,6) yields integer number 1-6.

SRAND(0 or a negative number) could clear the random seed and return it to normal

SORT(V,TYPE). Sorts an array. If type=FALSE sorts in reverse. If TRUE or not included sorts ascending by default. if SORT is called with no variable before it SORT(V,TYPE) instead of res=SORT(V,TYPE) then results are sorted directly into input array

New command. INSTR() to search for a string within a substring. PRINT INSTR("APPLE","PL") yields 3.
New command. RINSTR() to search for a string within a substring in reverse. PRINT INSTR("APPLE,"P") yields 3.

New command REPLACE() to replace all occurances of string within string recursively.
dessert="APPLE PIE"
chang now contains "CHERRY PIE"
if done without argument, just REPLACE(dessert,"APPLE,"CHERRY") then variable dessert is modified directly

New command CHAR(Str,I) to return a single character of a string, shorter version of SUB(Str,I,I)
New command MID(Str,A,B) to return a parsed string position A length of B. This is different from standard SUB()

New command FORV. This is similar to FOR/Do with the exception that the variable it uses can be manipulated and could be previously defined, for instance.

FORV I=1,10 DO

will yield: 1, 3, 5, 7, 9
After the loop it would contain 11

RECT2() to draw a rectangle where 3rd and 4th arguments are not x2 and y2 but width and height,
same with RECTFILL2()

Collision check with SPR() and other SPR() by pixel.
IF COLLISION(spr1,x,y,spr2,x,y,xtra) return FLAG of 2nd sprite, xtra means to not check pixels, just 8x8 area colliding

COLLISION2 is same but returns FLAG of 1st sprite, also xtra to not check pixels just 8x8 area colliding

IF MAPCOLLISION(spr1,x,y,xtra) where x and y are true location in map. Return value is FLAG of tile sprite if collision. Like above xtra if TRUE means to not check pixels but 8x8 area colliding.

I would really like these next ones, READTEXT() and WRITETEXT()
Read and write true text files, also higher level access directory. Can only read and write to text .TXT file for security.

mesg=READTEXT("message.txt") mesg now is a single string and contains every character from message.txt file
hisc=READLINES("hiscore.txt") hisc now has an array with as many elements as in text, one per CR delimited line. 7-bit text "@clip" is also possible.

WRITETEXT(hisc,"hiscore.txt") saves an array with as many elements in there as external text file
WRITETEXT(mesg,"message.txt") if not an array, instead saves the single string as the entire single file
7-bit text "@clip" is also possible.

next line asterisks do not appear properly, replace # with asterisk when reading
DIR(dir) where dir is a string that can contain "#.txt" to see only txt files or "#" to see every file
also use "flip#" to show every file that begins with "flip"

see=READDIR(dir) SEE now has an array with as many elements as from DIR(), one per file listed

DELETE(filename) - for safety file type can only be .TXT.

RENAME(filename1,filename2) - for safety file type can only be .TXT.

There should be no ability to delete directories. Keep it safe.

WEBSITE(url) ... loads website with default browser and opens accepted so long as URL address beginning has, "www.lexaloffle.com" to confirm staying within Lexaloffle community.


Read and write shared messages. Possible to make CHAT this way.
ANYKEY() ... is TRUE if user has pressed some key, any key, usually followed up by SEND, do not wait for key
SEND(string) sends string to everyone running this program now

ACCEPT ... is TRUE if someone has sent a message remotely and not yet been received locally, usually followed up by RECV. This is on a first-come-first-served basis. If there are several messages, it gets each of them one at a time.

RECV(string) empty until someone sends a string via ACCEPT()
For safety, strings cannot be more than 64-characters each. (256 also if you like, should set a limit though)


  END --endif
  END --endif
UNTIL FOREVER - - (loop forever)
P#67574 2019-09-12 04:31 ( Edited 2019-10-19 15:51)

View Older Posts
Follow Lexaloffle:        
Generated 2020-06-05 17:27 | 0.195s | 4194k | Q:203