Monday, April 25, 2011

First real program

Today I was looking back over the first real program I ever wrote. It was for my Casio fx-9750G plus graphing calculator which I had in college. The calculator had a basic derived language that was quite powerful, if at times difficult to use due to having to navigate the menus to insert keywords. I had played around a bit with the programs given in the book, and a few games that I had found on the net, but I wanted to make something a bit more interesting, something you could actually play with a friend (and I was thinking an AI, but never got round to that).

I had played a game where you had to set the power, and the aim was to hit a target. However it was quite simplistic, and you only got one shot before it changed the position, which was a bit frustrating. I took the idea, and the basic formula for the projectile from that game, and made ARTILERY (only one L as the name of a program could be a max of 8 chars). It's basically a simple tank game, with three weapons (of successively smaller damage areas, but higher damage), with alternating turns, and wind. Source code follows. Note that the comments were added by me when I typed it up (previously I wrote it out on a piece of refill). I was actually surprised how much of the mechanics I remembered, or could figure out without too much difficulty. Feel free to do the laborious task of typing this out into your calculator if you have one and want to play.

# This is a simple artillery game
# 1502 bytes
# -> means the assignment operator, →
# => means the single line then operator, ⇒
# Try holding the keys down rather than just pressing them when playing

ClrText                                                    # [SHIFT][PRGM][F6][F1][F1] for ClrText
"    --ARTILLERY--"
" "
" "
"  0=HELP 1~9=START"?->A
If A=0
Then ClrText
"<-/-> = CHANGE WEAPONUP/DOWN = POWER+5/-5 F5/F6 = POWER-1/+1"       # [F6][F5] for /
"+/- = ANGLE+5/-5"
"EXE = FIRE"◢
IfEnd
ViewWindow 0,80,0,0,30,0,0,4,.1
AxesOff                                                    # [SHIFT][MENU][F4][F2] for AxesOff
Deg                                                        # Sets angles to degrees, [SHIFT][MENU][F1][F1] for 'Deg'
ᴇ2->C~D                                                    # ᴇ=EXP, C=p1 hp, D=p2 hp
Int 51Ran#-25->W                                           # W=wind
0->Z                                                       # Z=0/1 => plyr 1/2's turn
28Ran#+7->E                                                # E=left player's position
28Ran#+45->F                                               # F=right player's position
F-1.5->P
E+1.5->O
Lbl 1                                                      # Lbl 1 = start a player's turn
Cls
F-Line E,0,E+3,2                                           # [SHIFT][F4][F6][F2][F2] for F-Line
F-Line F,0,F-3,2
F-Line E+3,0,E+1.5,1
F-Line F-3,0,F-1.5,1
O->Q
P->O
Q->P
Text 1,1,"WIND="                                           # [SHIFT][F4][F6][F6][F2] for Text 
Text 8,1,"DIR="
Text 1,78,"POWER="
Text 8,78,"ANGLE="
Text 1,40,"WEAPON="
Text 15,1,"PLYR 1="
Text 15,78,"PLYR 2="
Text 15,43,"TIME="
15->T                                                      # T=time
0->N                                                       # N=0 on the first iteration of main loop
45->A                                                      # A=angle
30->V                                                      # V=velocity (power)
1->G                                                       # G=1/2/3 shrapnel/explosive/bomb
If Z=0
Then C->S
D->C
S->D
1->Z
Text 22,10,"^"
1->R                                                       # R=direction multiplier
Else 0->Z
Text 22,110,"^"
-1->R
IfEnd
Text 15,30,C                                               # Show each player's hp
Text 15,107,D
If Z=0
Then D->S
C->D
S->C
IfEnd
Lbl 2                                                      # Lbl 2 = main game loop
Int 51Ran#-25->B                                           # Set the wind
B>W=>W+1->W
BW-1->W
Text 1,25,"   "                                            # 3 spaces to cover the previous wind
Text 1,25,W
W>0=>Text 8,24,"->"                                        # Set the wind direction arrow
W<0=>Text 8,24,"<-"
Text 15,65,"  "                                            # 2 spaces to cover the previous time
Text 15,65,T
T=0=>Goto 4                                                # Time's up
T-1->T
Getkey->K                                                  # Read keypad input [SHIFT][VARS][F6][F4][F2] for Getkey
N=0=>Goto 3                                                # Process keypress on first iteration to draw everything, skip later
K=0=>Goto 2                                                # Restart the event loop if no keypress
Lbl 3                                                      # Lbl 3 = process key press
N=0=>1->N
K=27=>G≠3=>G+1->G                                          # Pressed -> to get next weapon
K=38=>G≠1=>G-1->G                                          # Pressed <- to get previous weapon
G=1=>Text 8,40,"SHRAPNEL "                                 # Spaces for padding to ensure old text is covered
G=2=>Text 8,40,"EXPLOSIVE"
G=3=>Text 8,40,"BOMB     "
K=28=>V+5->V                                               # Pressed up to increase velocity by 5
K=29=>V+1->V                                               # Pressed F6 to increase velocity by 1
K=37=>V>0=>V-5->V                                          # Pressed down to decrease velocity by 5
K=39=>V>0=>V-1->V                                          # Pressed F5 to decrease velocity by 1
Text 1,106,V                                               # Write the current velocity on screen
K=42=>A+5->A                                               # Pressed + so increase angle by 5
K=32=>A>0=>A-5->A                                          # Pressed - so decrease angle by 5
Text 8,106,A                                               # Write the current angle on screen
If K=31                                                    # Pressed EXE so fire!
Then Graph(X,Y)=(R(.5V+5+.35RWT)cos A✕T+P,(.5V+5)sin A✕T-4.9T²       # Draws the shot, [SHIFT][F4][F5][F3] for 'Graph(X,Y)=('
(.5V+5)sin A÷4.9->T                                        # T=Time before projectile hit
R(.5V+5+.35RWT)cos A✕T+P->L                                # L=X coord (location) projectile hit
If G=1                                                     # Draw the blast (shrapnel)
Then For -5->Y To 5 Step 10
F-Line L,0,L+2Y,1
F-Line L,0,L+4⌟3Y,1.5
F-Line L,0,L+.5Y,2
Next
L≤O+10=>L≥O-10=>D-30+Int (2Abs (L-O))->D                   # Deal damage, based on distance from blast
IfEnd
If G=2                                                     # explosive
Then For -1->Y To 1 Step 2
F-Line L,0,L-5Y,.75
F-Line L,0,L-3Y,1.5
F-Line L,0,L-1.5Y,2
Next
L≤O+5=>L≥O-5=>D-50+Int (6Abs (L-O))->D
IfEnd
If G=3                                                     # bomb
Then F-Line L-2.5,0,L+2.5,0
F-Line L-1.5,.5,L+1.5,.5
F-Line L-1,1,L+1,1
L≤O+2.5=>L≥O-2.5=>D-80+Int (16Abs (L-O))->D
IfEnd
Text 30,49,"BOOM!"
If D≤0                                                     # hp≤0, so game over
Then Text 45,33,"PLAYER 2 WINS!"
If Z=0
Then Text 15,30,"  "                                       # 2 spaces
Text 15,30,D                                               # Print out final hp
Else Text 45,61,1                                          # Overwrite the 2 with a 1 in "PLAYER 2 WINS!"
Text 15,107,"  "                                           # 2 spaces
Text 15,107,D
IfEnd
Stop                                                       # [SHIFT][VARS][F2][F4] for Stop
IfEnd
Goto A
IfEnd
Goto 2
Lbl 4
Text 30,42,"TIME UP!"
Lbl A
Text 40,42,"PRESS EXE"◢
Goto 1

Saturday, April 23, 2011

Decoding email attachment

Yesterday, I received an email with an attachment (in gmail), but for some reason it showed the attachment was there, but no download link (though it appears now). Wanting to view the attachment, I did some brute force hackery. In gmail you can hit the link "show original" which shows the original text of the email, including the attachments. So I saved this as a text file, deleted everything but the base64 encoded data (i.e the attachment). Then I used the base64 command line tool (imaginatively called base64), that everyone should have installed already, to decode this data, and to just a little surprise, it all worked. I was quite pleased with that. I also just had a look at the wikipedia page for base64 encoding to see how it works. You should too, it's quite simple, but effective.

Monday, April 18, 2011

Underoath

I sometimes forget how much I love listening to Underoath. They're such a great band, particularly their last three albums (Define the Great Line, Lost In The Sound of Separation, and Ø (Disambiguation)). Sometimes it can be a bit heavy, and I'm not in the mood for it, but so often it just fits perfectly. Good music, good lyrics (even if they can be hard to interpret at times).

I can just sit and listen for ages. Or I sit and listen with the lyrics in front of me (Ctrl+T in banshee), and finally learn what they're actually saying. They usually speak of the troubles of life, particularly life as a Christian, in a world where it can be hard.

For instance, the song I'm listening to now, A Fault Line, A Fault of Mine has the verse:

I was lying when I said, I was looking up
I was too scared to show what I am
Bear with me, bear with me, this is all I have left
This might be more than a simple conversation

Which is exactly how I feel at times. I find it encouraging, and it's really helped me through some times when I haven't been feeling myself. Give them a listen, you might enjoy it (or get a headache).

Saturday, April 16, 2011

gnome terminal unlimited scrollback

A recent, and very handy feature that came out in gnome terminal (my currently preferred terminal program, basically because I use gnome), was unlimited scrollback. I thought I'd try it for a while, to see if it would have any negative effects on performance (particularly memory use), as it'd be a useful thing to have, as there have been a number of times I've lost output that I would've liked to have kept off the top of the buffer.

The first thing I did was to fill the terminal with a whole lot of output, to see what would happen. My preferred way of doing this was simply $ base64 < /dev/urandom, which avoids the problem of strange things happening due to the non-printable characters. After running that for a while, I didn't notice the memory usage increasing, but also couldn't find any new large files in my home directory, or /tmp. Which left me a little confused.

They're probably using some kind of fancy compression was my next thought (despite random data being impossible to compress). So I changed my command to run as $ base64 < /dev/urandom | tee tmp to make a temporary file of the output as well as spitting it out. Compressing that with xz, bzip2 and gz all shrunk it to about 70% of the file size (remember, it's base64 encoded random data, so we can actually compress it). As a sidenote, the compressed base64 random data was about 5% larger than just the pure random data - which itself can't be compressed. So this led me to think that they couldn't be compressing it all away to virtually nothing, it's got to be somewhere. (Meanwhile, I left the command running, filling up my terminal).

My next port of call was to have a look at the source code. So I git cloned the gnome-terminal repo, which it turns out uses another gnome library, vte, which I also cloned. I could find where the setting was defined, and it turns out "unlimited" just means there are a max G_MAXLONG in the buffer (which is effectively infinite). I also found mention in a comment that it was saving it to disk, but I couldn't find where it was saving the data.

But then I saw the light. I could just look at what files gnome-terminal had open, so lsof to the rescue. Then I found it was being sneaky, it had a number of files called /tmp/vteXYZ1tv open, but it had already deleted them. Thus you can't see them when browsing, and they will be removed when the program closes. This makes sense, it means that when the process is closed, it doesn't matter how (at least I think), the space of the files can be reclaimed, i.e. we won't get leftover files on a program crash, or a kill -9. They can be restored though, my way (there are probably others), was to do a ls -l /proc/<gnome-terminal pid>/fd to see what they point to. Then you can cat these to make a new file. These are just a verbatim copy of the terminal output. No compression. No nothing. As it turns out, one of my terminal history's was almost 900 MB! But that was only after random data being spat out very quickly for quite a while, unlikely to happen in ordinary usage. For the foreseeable future though, I think I'll keep this option checked, as I can live with a bit of disk usage for the handiness.