gabehabe Cool blog, bro.

28Sep/090

My First Android App: Brainfuck

My first app!

** EDIT: Just realised input doesn’t work: It brings up the input dialog, but I forgot to save it anywhere! Guess I was a little too excited to get publishing ;). I’ll try to find time to fix it tomorrow! Apologies! **

Download:
Download on android!

Okay, so it’s not gonna get a very good rating… it’s not very attractive, and I really don’t think many people are going to understand Brainfuck.

That said, it was a fun little app to write… and I must admit, I really didn’t give the android SDK a fair chance. (Mind, it’s changed a hell of a lot since I first tried it back when android was first released to the general public!)

Code for the app, broken into two parts: (the activity and the layout)

First off, the main code for the Java activity:

package gabehabe.brainfuck;
 
import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;
import android.widget.EditText;
import android.widget.TextView;
import android.text.InputFilter;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.widget.TabHost.OnTabChangeListener;
 
public class Brainfuck extends TabActivity implements OnTabChangeListener {
	String input;
	TabHost tabs;
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    setContentView(R.layout.main);
 
	    this.tabs = getTabHost();
 
	    tabs.addTab(tabs.newTabSpec("tab_code").setIndicator("Code").setContent(R.id.code));
	    tabs.addTab(tabs.newTabSpec("tab_run").setIndicator("Run").setContent(R.id.interpreted));
	    tabs.addTab(tabs.newTabSpec("tab_help").setIndicator("Help").setContent(R.id.help));
	    tabs.setOnTabChangedListener(this);
 
 
	    tabs.setCurrentTab(0);
	}
 
	@Override
	public void onTabChanged(String label) {
		if(label == "tab_run") {
			final Brainfuck bf = this;
			final TextView interpreted = (TextView)this.findViewById(R.id.interpreted);
			interpreted.setText("");
			final EditText edt = (EditText)this.findViewById(R.id.code);
			String t = edt.getText().toString();
			int bytes_pos = 0;
			int loop_pos = -1;
			char [] bytes = new char[300];
			// initialise and make sure everything's 0
			for(int i = 0; i < 300; i++) {
				bytes[i] = 0;
			}
			for(int i = 0; i < t.length(); i++) {
				switch(t.charAt(i)) {
					case '+':
						++bytes[bytes_pos];
						break;
					case '-':
						--bytes[bytes_pos];
						break;
					case '>':
						++bytes_pos;
						break;
					case '< ':
						--bytes_pos;
						break;
					case '.':
						StringBuffer b = new StringBuffer();
						b.append(interpreted.getText()).append(bytes[bytes_pos]);
						interpreted.setText(b.toString());
						break;
					case ',':
					    AlertDialog.Builder alert = new AlertDialog.Builder(this);
 
					    alert.setTitle("Enter Character");
					    alert.setMessage("Program is requesting input!");
 
					    // Set an EditText view to get user input 
					    final EditText input = new EditText(this);
					    InputFilter[] FilterArray = new InputFilter[1];
					    FilterArray[0] = new InputFilter.LengthFilter(1);
					    input.setFilters(FilterArray);
 
					    alert.setView(input);
 
					    alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					    public void onClick(DialogInterface dialog, int whichButton) {
					    	bf.input = input.getText().toString();
					      }
					    });
 
					    alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
					      public void onClick(DialogInterface dialog, int whichButton) {
					    	 bf.input = "";
					      }
					    });
					    alert.show();
					    break;
					case '[':
						loop_pos = i;
						break;
					case ']':
						if (loop_pos != -1) {
							if(bytes[bytes_pos] == 255) { // stupid java... ¬_¬
								bytes[bytes_pos] = 0;
							}
							if (bytes[bytes_pos] != 0) {
								i = loop_pos;
							} else {
								loop_pos = -1;
							}
						}
						break;
				}
			}
		}
	}
}

And now the code for the actual layout (XML format)

< ?xml version="1.0" encoding="utf-8"?>
<tabhost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <linearlayout android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <tabwidget android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <framelayout android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">
 
            /* tab 1 -- code entry */
            <edittext android:id="@+id/code" 
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent" 
              android:background="@android:drawable/editbox_background"
            />
 
            /* tab 2 -- run */
            <scrollview xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
              <textview android:id="@+id/interpreted"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" 
              />
            </scrollview>
            /* tab 3 -- help */
            <scrollview xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
              <textview android:id="@+id/help"
      	          android:layout_width="fill_parent"
             	  android:layout_height="fill_parent" 
                  android:text="@string/help"
              />
            </scrollview>
    	</framelayout>
    </linearlayout>
</tabhost>

I'll no doubt be adding stuff, a menu for snippets, perhaps saving files and stuff... all good fun. Watch this space! :)

26Sep/091

Google Android: Games by Square Enix

At the time of writing this article, there are currently three apps on the android market by Square Enix. I’ve just bought, and tested, each one, just to write about them here, for you. So I hope you appreciate it. :)

The three games that I’m going to discuss in this article are:
Arkanoid – A clone of the original
Space Invaders – If you don’t remember this, you’re most likely incapable of reading this entry anyway.
And a third, which is very different. I’ll reserve any information until the end of this entry, but just know that it’s called Puzzle Bobble, and I like it a lot.

To start off, I’ll summarise Arkanoid and Space Invaders together: crap. Honestly, I would’ve expected great things, especially after Square-Enix released Space Invaders Extreme a little while back. (Screenshot borrowed from IGN.)

Square-Enix Space Invaders Extreme - PSP

But no such luck. :( They’re literally exact clones of the original games, complete with the terrible graphics. Granted, it’s nice to reminisce, but I’d rather reminisce in front of a ROM on an emulator than playing in a tiny window with a huge border, and paying a few quid to do it. The exact same goes for Arkanoid. A couple of quick screenshots,

Square-Enix Arkanoid on Android
Square-Enix Space Invaders on Android

Pretty disappointing, huh? :(

Now, it’s not all so bad. I’ve been playing Puzzle Bobble a bit, and it’s quite a nice game. Completely different to the Arkanoid and Space Invaders clones, frankly I find it hard to even believe that they were written by Square Enix. :(

But, onto the positive. While it’s the most expensive game that Square Enix currently offer on the Android market, it’s a great one. The graphics are nice, and it’s actually really cute ^__^ (similar style to Yosumin, which is completely unrelated to this post, but just to give you an idea!)

The idea is similar to a game I used to play on Sky games about a decade ago, with bees. I forget the name, so this isn’t really going to help you to get an idea of what the game is. It’s one of those games where you have bubbles at the top, and you have to shoot differently coloured bubbles to match them. If you get 3 or more in a row, they will chain and fall, dropping anything which is attached to them. Screenshots are more descriptive.

Square-Enix Puzzle Bobble on Android
Square-Enix Puzzle Bobble on Android

10Sep/092

wxWidgets: Keyboard Shortcuts without a Menu

Quick entry. Sort of a preview. I’m working on a tutorial for dream.in.code about creating keyboard shortcuts in a wxWidgets application (particularly using C++), and figured I’d share the code here, too.

(After I’ve finally gotten around to installing this syntax highlighting plugin for WordPress)

Aaaaannddd… Done!

Right. Back onto the original topic. Damn sidetracked mind. So, when I write a tutorial, I write a whole chunk of code first, and then add the tutorial content around it. Here’s the code for allocating keyboard shortcuts to do different stuff in wxWidgets without using menu items.

// basic setup code, I'll fly past this. If you're not familiar, check out this tutorial:
// http://www.dreamincode.net/forums/showtopic66948.htm
 
#include <wx/wx.h>
 
class app : public wxApp {
    public:
        virtual bool OnInit();
    private:
        wxTextCtrl* txt;
        wxCheckBox* chk;
 
        void key_shortcut(wxKeyEvent&);
        DECLARE_EVENT_TABLE()
};
 
// if you're not familiar with events, check out this tutorial:
// http://www.dreamincode.net/forums/showtopic67058.htm
 
BEGIN_EVENT_TABLE(app, wxApp)
    EVT_KEY_DOWN(app::key_shortcut)
END_EVENT_TABLE()
 
bool app::OnInit() {
    wxFrame* win = new wxFrame(NULL, wxID_ANY, wxT("Keyboard Shortcuts, No Menu!"), wxDefaultPosition, wxSize(250, 125));
    win->Show(true);
 
    this->txt = new wxTextCtrl(win, wxID_ANY, wxT("Press Ctrl+G to append text to me"), wxPoint(0,0), wxSize(250, 50), wxTE_MULTILINE);
    this->chk = new wxCheckBox(win, wxID_ANY, wxT("Press Ctrl+Left to toggle me."), wxPoint(0, 55), wxDefaultSize);
 
    return true;
}
 
// this is the method I'll be focusing on. The key_shortcut event which we create
// to do fancy stuff without adding billions of menu items
 
void app::key_shortcut(wxKeyEvent& e) {
    // of course, it doesn't have to be the control key. You can use others:
    // http://docs.wxwidgets.org/stable/wx_wxkeyevent.html
    if(e.GetModifiers() == wxMOD_CONTROL) {
        switch(e.GetKeyCode()) {
            case 'G': // can return the upper ASCII value of a key
                // do whatever you like for a Ctrl+G event here!
                this->txt->AppendText(wxT(" gabehabe ftw!"));
                break;
            case WXK_LEFT: // we also have special keycodes for non-ascii values.
                // get a full list of special keycodes here:
                // http://docs.wxwidgets.org/stable/wx_keycodes.html
                this->chk->SetValue(!this->chk->GetValue());
                break;
            default: // do nothing
                break;
        }
    }
}
 
IMPLEMENT_APP(app)

Link to follow when the tutorial is completed and approved.

As promised, here’s the tutorial in all it’s glory:
wxWidgets keyboard shortcuts with no menu