How to resolve the algorithm Wireworld step by step in the GML programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Wireworld step by step in the GML programming language

Table of Contents

Problem Statement

Wireworld is a cellular automaton with some similarities to Conway's Game of Life. It is capable of doing sophisticated computations with appropriate programs (it is actually Turing complete), and is much simpler to program for. A Wireworld arena consists of a Cartesian grid of cells, each of which can be in one of four states. All cell transitions happen simultaneously. The cell transition rules are this:

Create a program that reads a Wireworld program from a file and displays an animation of the processing. Here is a sample description file (using "H" for an electron head, "t" for a tail, "." for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate: While text-only implementations of this task are possible, mapping cells to pixels is advisable if you wish to be able to display large designs. The logic is not significantly more complex.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Wireworld step by step in the GML programming language

Source code in the gml programming language

//Create event
/*
Wireworld first declares constants and then reads a wireworld from a textfile.
In order to implement wireworld in GML a single array is used.
To make it behave properly, there need to be states that are 'in-between' two states:
0 = empty
1 = conductor from previous state
2 = electronhead from previous state
5 = electronhead that was a conductor in the previous state
3 = electrontail from previous state
4 = electrontail that was a head in the previous state
*/
empty = 0;
conduc = 1;
eHead = 2;
eTail = 3;
eHead_to_eTail = 4;
coduc_to_eHead = 5;
working = true;//not currently used, but setting it to false stops wireworld. (can be used to pause)
toroidalMode = false;
factor = 3;//this is used for the display. 3 means a single pixel is multiplied by three in size.

var tempx,tempy ,fileid, tempstring, gridid, listid, maxwidth, stringlength;
tempx = 0;
tempy = 0;
tempstring = "";
maxwidth = 0;

//the next piece of code loads the textfile containing a wireworld.
//the program will not work correctly if there is no textfile.
if file_exists("WW.txt")
{
fileid = file_text_open_read("WW.txt");
gridid = ds_grid_create(0,0);
listid = ds_list_create();
    while !file_text_eof(fileid)
    {
    tempstring = file_text_read_string(fileid);
    stringlength = string_length(tempstring);
    ds_list_add(listid,stringlength);
        if maxwidth < stringlength
        {
        ds_grid_resize(gridid,stringlength,ds_grid_height(gridid) + 1)
        maxwidth = stringlength
        }
        else
        {
        ds_grid_resize(gridid,maxwidth,ds_grid_height(gridid) + 1)
        }
        
        for (i = 1; i <= stringlength; i +=1)
        {
            switch (string_char_at(tempstring,i))
            {
            case ' ': ds_grid_set(gridid,tempx,tempy,empty); break;
            case '.': ds_grid_set(gridid,tempx,tempy,conduc); break;
            case 'H': ds_grid_set(gridid,tempx,tempy,eHead); break;
            case 't': ds_grid_set(gridid,tempx,tempy,eTail); break;
            default: break;
            }
        tempx += 1;
        }
    file_text_readln(fileid);
    tempy += 1;
    tempx = 0;
    }
file_text_close(fileid);
//fill the 'open' parts of the grid
tempy = 0;
    repeat(ds_list_size(listid))
    {
    tempx = ds_list_find_value(listid,tempy);
        repeat(maxwidth - tempx)
        {
        ds_grid_set(gridid,tempx,tempy,empty);
        tempx += 1;
        }
    tempy += 1;
    }
boardwidth = ds_grid_width(gridid);
boardheight = ds_grid_height(gridid);
//the contents of the grid are put in a array, because arrays are faster.
//the grid was needed because arrays cannot be resized properly.
tempx = 0;
tempy = 0;
    repeat(boardheight)
    {
        repeat(boardwidth)
        {
        board[tempx,tempy] = ds_grid_get(gridid,tempx,tempy);
        tempx += 1;
        }
    tempy += 1;
    tempx = 0;
    }
//the following code clears memory
ds_grid_destroy(gridid);
ds_list_destroy(listid);
}

//Step event
/*
This step event executes each 1/speed seconds.
It checks everything on the board using an x and a y through two repeat loops.
The variables westN,northN,eastN,southN, resemble the space left, up, right and down respectively, 
seen from the current x & y.
1 -> 5 (conductor is changing to head)
2 -> 4 (head is changing to tail)
3 -> 1 (tail became conductor)
*/

var tempx,tempy,assignhold,westN,northN,eastN,southN,neighbouringHeads,T;
tempx = 0;
tempy = 0;
westN = 0;
northN = 0;
eastN = 0;
southN = 0;
neighbouringHeads = 0;
T = 0;

if working = 1
{
    repeat(boardheight)
    {
        repeat(boardwidth)
        {
            switch board[tempx,tempy]
            {
            case empty: assignhold = empty; break;
            case conduc:
                neighbouringHeads = 0;
                if toroidalMode = true //this is disabled, but otherwise lets wireworld behave toroidal.
                {
                    if tempx=0
                    {
                    westN = boardwidth -1;
                    }
                    else 
                    {
                    westN = tempx-1;
                    }
                    if tempy=0
                    {
                    northN = boardheight -1;
                    }
                    else 
                    {
                    northN = tempy-1;
                    }
                    if tempx=boardwidth -1
                    {
                    eastN = 0;
                    }
                    else 
                    {
                    eastN = tempx+1;
                    }
                    if tempy=boardheight -1
                    {
                    southN = 0;
                    }
                    else 
                    {
                    southN = tempy+1;
                    }

                T=board[westN,northN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[tempx,northN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[eastN,northN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[westN,tempy];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[eastN,tempy];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[westN,southN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[tempx,southN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                T=board[eastN,southN];
                    if T=eHead or T=eHead_to_eTail
                    {
                    neighbouringHeads += 1;
                    }
                }
                else//this is the default mode that works for the provided example.
                {//the next code checks whether coordinates fall outside the array borders.
                //and counts all the neighbouring electronheads.
                    if tempx=0
                    {
                    westN = -1;
                    }
                    else 
                    {
                    westN = tempx - 1;
                    T=board[westN,tempy];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if tempy=0
                    {
                    northN = -1;
                    }
                    else 
                    {
                    northN = tempy - 1;
                    T=board[tempx,northN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if tempx = boardwidth -1
                    {
                    eastN = -1;
                    }
                    else 
                    {
                    eastN = tempx + 1;
                    T=board[eastN,tempy];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if tempy = boardheight -1
                    {
                    southN = -1;
                    }
                    else 
                    {
                    southN = tempy + 1;
                    T=board[tempx,southN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    
                    if westN != -1 and northN != -1
                    {
                    T=board[westN,northN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if eastN != -1 and northN != -1
                    {
                    T=board[eastN,northN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if westN != -1 and southN != -1
                    {
                    T=board[westN,southN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                    if eastN != -1 and southN != -1
                    {
                    T=board[eastN,southN];
                        if T=eHead or T=eHead_to_eTail
                        {
                        neighbouringHeads += 1;
                        }
                    }
                }
                    if neighbouringHeads = 1 or neighbouringHeads = 2
                    {
                    assignhold = coduc_to_eHead;
                    }
                    else 
                    {
                    assignhold = conduc;
                    }
                break;
                
            case eHead: assignhold = eHead_to_eTail; break;
            case eTail: assignhold = conduc; break;
            default: break;
            }
        board[tempx,tempy] = assignhold;
        tempx += 1;
        }
    tempy += 1;
    tempx = 0;
    }
}

//Draw event
/*
This event occurs whenever the screen is refreshed.
It checks everything on the board using an x and a y through two repeat loops and draws it.
It is an important step, because all board values are changed to the normal versions:
5 -> 2 (conductor changed to head)
4 -> 3 (head changed to tail)
*/
//draw sprites and text first

//now draw wireworld
var tempx,tempy;
tempx = 0;
tempy = 0;

repeat(boardheight)
{
    repeat(boardwidth)
    {
        switch board[tempx,tempy]
            {
            case empty: 
            //draw_point_color(tempx,tempy,c_black); 
            draw_set_color(c_black);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            break;
            case conduc: 
            //draw_point_color(tempx,tempy,c_yellow); 
            draw_set_color(c_yellow);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            break;
            case eHead:
            //draw_point_color(tempx,tempy,c_red);
            draw_set_color(c_blue);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            draw_rectangle_color(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,c_red,c_red,c_red,c_red,false);
            break;
            case eTail: 
            //draw_point_color(tempx,tempy,c_blue);
            draw_set_color(c_red);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            break;
            case coduc_to_eHead:
            //draw_point_color(tempx,tempy,c_red);
            draw_set_color(c_blue);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            board[tempx,tempy] = eHead;
            break;
            case eHead_to_eTail: 
            //draw_point_color(tempx,tempy,c_blue);
            draw_set_color(c_red);
            draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false);
            board[tempx,tempy] = eTail; 
            break;
            default: break;
            }
    tempx += 1
    }
tempy += 1;
tempx = 0;
}
draw_set_color(c_black);

  

You may also check:How to resolve the algorithm URL parser step by step in the Wren programming language
You may also check:How to resolve the algorithm Sum multiples of 3 and 5 step by step in the Rust programming language
You may also check:How to resolve the algorithm Integer comparison step by step in the Icon and Unicon programming language
You may also check:How to resolve the algorithm Letter frequency step by step in the TUSCRIPT programming language
You may also check:How to resolve the algorithm Hostname step by step in the BaCon programming language