Category: Geeky

  • Actual fullscreen text-console on Windows 7/8

    You can’t put the old CMD.EXE in fullscreen anymore, but there is replacement called Console2 that has some cool features. Do not set Console2 as your standard console in Windows you use shortcuts like the Visual Studio Command Prompt, because the different behaviors will set Console2 in an infinite loop.

    When installed, you can open the Settings window to tweak appearance, like hide the scrollbars and such. When done, you toggle fullscreen mode using the F11 key. This is what you get:

    fullscreen

    Update 2014-08-23: The latest version with the fullscreen option is 1.8.0. I am hosting it here.

  • Commodore 128 bitmap graphics 2/2

    Part 1. Part 2.

    On the Commodore 128, the screen is divided into characters.

    1

    Each character consists of eight eight-pixel lines (bytes), which make a total of 64 pixels per character.

    2

    Each pixel pair represent one of four available colors in multicolor mode. This can be demonstrated using this simple code:

    10 GRAPHIC 3, 1 : REM CREATE CLEAN MULTICOLOR DISPLAY
    20 DRAW 1, 0, 0 : REM DRAW USING COLOR 1
    30 DRAW 2, 0, 1 : REM DRAW USING COLOR 2
    40 DRAW 3, 0, 2 : REM DRAW USING COLOR 3

    Now, this pattern is shown:

    3

    If you add a line of code to change to high resolution graphics without clearing, we can see that two turned off pixels represent the first color, one off and one on represent color 2, one on and one off represent color 3 and two turned on pixels represent color 4.

    50 GRAPHIC 1, 0 : REM CHANGE TO HIGH RESOLUTION WITHOUT CLEARING

    4

    The graphics memory is movable. This command places the graphics memory at 2000 (8192 in decimal):

    POKE 53272, (PEEK(53272) AND 240) OR 8

    The eight pixel pattern of each row in a character can be described using binary 00000000 for all off to 11111111 for all on (0 to 255 in decimal). Placing the number 00011011 (27) will draw one multicolor pixel of each color on the first line. 00 is color 0 (background), 01 is color 1, 10 is color 2 and 11 is color 3.

    10 GRAPHICS 3, 1
    20 POKE 53272, (PEEK(53272) AND 240) OR 8
    30 POKE 8192, 27

    5

  • Commodore 128 bitmap graphics 1/2

    Part 1. Part 2.

    When Commodore 128 vector graphics can’t provide the desired details, there is an option to do bitmap graphics. The 128 have a built in command for creating pixel perfect graphics called SPRSAV. You can create a pattern using the built-in editor (SPRDEF)…

    01

    …and transfer the data into a string variable, and then copy that data to the screen, like so:

    10 COLOR 0, 13
    20 COLOR 4, 13
    30 COLOR 1, 1
    40 COLOR 2, 8
    50 COLOR 3, 12
    60 GRAPHIC 3, 1
    70 SPRSAV 1, A$
    80 GSHAPE A$, 10, 10, 2 : REM DRAW SPRITE AT 10, 10
    90 GSHAPE A$, 20, 11, 2
    100 GSHAPE A$, 30, 12, 2

    02

    This should be enough for anyone, but if you like, you can also access the graphics memory directly.

  • Commodore 128 vector graphics

    The Commodore 128 have a rich API for making colorful vector graphics. The low resolution (160×200) color mode allows you to make the classic “Forrest Gump” smiley using these five lines of code:

    10 COLOR 0, 13 : REM GREY BACKGROUND
    20 COLOR 4, 13 : REM GREY BORDER
    30 COLOR 1, 1 : REM COLOR 1 IS BLACK
    40 COLOR 2, 8 : REM COLOR 2 IS YELLOW
    50 COLOR 3, 12 : REM COLOR 3 IS SHADOW (DARK GREY)
    60 GRAPHIC 3, 1 : REM LOWRES MULTICOLOR MODE
    70 CIRCLE 3, 80, 101, 49, 99 : REM SHADOW OUTLINE
    80 PAINT 3, 80, 101 : REM SHADOW FILL
    90 CIRCLE 2, 97, 99, 49, 99 : REM SMILEY SIZE
    100 PAINT 2, 79, 99 : REM SMILEY FILL
    110 CIRCLE 1, 79, 99, 49, 99 : REM SMILEY CONTOUR
    120 CIRCLE 1, 65, 70, 8, 22 : REM LEFT EYE
    130 PAINT 1, 65, 70 : REM LEFT EYE COLOR
    140 CIRCLE 1, 92, 70, 8, 22 : REM RIGHT EYE
    150 PAINT 1, 92, 70 : REM RIGHT EYE COLOR
    160 CIRCLE 1, 79, 99, 39, 85, 90, 280 :REM MOUTH

    smile

    To exit the program on a real 128, press Runstop + Restore. On the Vice emulator, press Caps Lock + Page Up. However, the Commodore 128 API is not very suitable for bitmap graphics. For that, other Commodore Basic strategies are more suitable.

  • Action Biker

    Nu har jag stulit så mycket jag bara kan: Rob Hubbards komposition, Trevor Horns sound (efter bästa förmåga). Detta är en cover på soundtracket till Action Biker från 1985.

  • Evolutionary sudoku

    This is a successful attempt to use an evolutionary algorithm to generate a sudoku board. A complete board is created after usually less than a million iterations, sometimes after a couple of hundred generations.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
       class Program
       {
          static void Main(string[] args)
          {
             var s = new Sudoku();
             s.Display();
             Console.Write("Done. Press enter to quit.");
             Console.ReadLine();
          }
       }
    
       class Sudoku
       {
          int[,] field = new int[9,9];
          const int mutation_speed = 3;
          const int dead_end_limit = 60000;
    
          public Sudoku()
          {
             var r = new Random();
             //Create a list of possible characters on the game field.
             var l = new List<int>();
             for (var i = 1; i < 10; i++)
                for (var j = 1; j < 10; j++)
                   l.Add(i);
             //Place them on the field randomly.
             for (var i = 0; i < 9; i++)
                for (var j = 0; j < 9; j++) {
                   var index = r.Next(0, l.Count);
                   var value = l[index]; l.RemoveAt(index);
                   this.field[j, i] = value;
                }
             //Prepare for score counting. Low is better.
             int score = int.MaxValue, iterations = 0, generations = 0,
             iterations_since_last_climb = 0;
             //Define how a mutation works - a random element swap.
             Action<int[,]> mutate = a => {
                var speed = (score > 2 ? mutation_speed : 1);
                for (var i = 0; i < speed; i++) {
                   int x1 = r.Next(0, 9), y1 = r.Next(0, 9),
                     x2 = r.Next(0, 9), y2 = r.Next(0, 9);
                   var v = a[x1, y1]; a[x1, y1] = a[x2, y2]; a[x2, y2] = v;
                }
             };
             //Show progress.
             Action status = () => {
                Console.Title = string
                   .Format("Score: {0:00} - Generations: {1:000} - " +
                   "Iterations: {2:000000}" +
                   " - Since last climb: {3:00000}",
                   score, generations, iterations, iterations_since_last_climb);
             };
             //Let evolution work.
             do {
                iterations++;
                //If adaptation has stopped, the parent must mutate.
                if (iterations_since_last_climb >= dead_end_limit) {
                   mutate(this.field);
                   score = this.GetScore(this.field);
                }
                //Breed two new sudokos and modify them slightly.
                int[,] child1 = (int[,])this.field.Clone();
                int[,] child2 = (int[,])this.field.Clone();
                mutate(child1); mutate(child2);
                //Check new scores.
                var child1score = this.GetScore(child1);
                var child2score = this.GetScore(child2);
                //Keep the best one, if any.
                Action<int[,], int> keep = (a, s) => {
                   this.field = (int[,])a.Clone(); score = s; generations++;
                   iterations_since_last_climb = 0; };
                if (child1score < score)
                   keep(child1, child1score);
                else if (child2score < score)
                   keep(child2, child2score);
                else
                   iterations_since_last_climb++;
                System.Threading.Thread.Yield();
                if ((iterations % 1000) == 0)
                   status();
    #if DEBUG
                this.Display();
                Console.CursorTop = 0;
    #endif
             } while (score > 0);
             status();
          }
    
          private int GetScore(int[,] p)
          {
             //Define how fitness is determined. A better solution is wanted.
             Func<int[,], int, int, bool> checkrow = (arr, x, y) => {
                var val = arr[x, y]; var count = 0;
                for (var i = 0; i < 9; i++)
                   if (arr[i, y] == val) count++;
                return (count == 1);
             };
             Func<int[,], int, int, bool> checkcol = (arr, x, y) => {
                var val = arr[x, y]; var count = 0;
                for (var i = 0; i < 9; i++)
                   if (arr[x, i] == val) count++;
                return (count == 1);
             };
             Func<int[,], int, int, bool> checksection = (arr, x, y) => {
                var section_x = x; while (!((section_x % 3) == 0)) section_x--;
                var section_y = y; while (!((section_y % 3) == 0)) section_y--;
                var val = arr[x, y]; var count = 0;
                for (var row = section_x; row < section_x + 3; row++)
                   for (var col = section_y; col < section_y + 3; col++)
                      if (arr[col, row] == val) count++;
                return (count == 1);
             };
             var score = 0;
             for (var i = 0; i < 9; i++)
                for (var j = 0; j < 9; j++) {
                   if (!(checkrow(p, j, i))) score++;
                   if (!(checkcol(p, j, i))) score++;
                   if (!(checksection(p, j, i))) score++;
                }
             return score;
          }
    
          public void Display()
          {
             for (var y = 0; y < 9; y++) {
                for (var x = 0; x < 9; x++)
                   Console.Write(field[x, y]);
                Console.WriteLine();
             }
          }
    
       }
    }

    Sudoku

    Update 2023-02-09: .NET 7.0 source code

  • Vic 20-labyrinten

    Vissa är säkert bekanta labyrintalgoritmen för Commodore 64, känd för de mer eller mindre slumpmässiga förutsättningarna som gör att en labyrint kan genereras med minimal kod. Koden jag tänker på är givetvis denna (Commodore Basic 2.0):

    10 PRINT CHR$(205.5+RND(1));:GOTO 10

    Koden är faktiskt inte klockren på C64. Med en hög upplösning (320*200 pixlar) i åtanke, satsade man på teckengrafik som alltid hade minst två pixlars bredd, eftersom detta gjorde grafiken mer visuell. Det ledde till att grafiken såg “trasig” ut när man körde program som inte tog hänsyn till detta.

    Vic 20 däremot, med sin låga upplösning (352*184), behövde inte använda dubbla pixlar på vertikala linjer. Och eftersom Vic 20 och C64 delade Basic (Commodore Basic 2.0) är labyrintkoden i fråga kompatibel med Vic 20. Om vi bryter ner koden, har vi följande:

    1. RND(1) är ett slumptal mellan 0 och strax under 1.

    2. 205,5 + RND(1) är antingen 205 eller 206 (\ eller / – inte backslash respektive slash – snarare diagonal åt höger och diagonal åt vänster) beroende på vad som tilldelas 205,5 eftersom CHR$ konverterar sin parameter till ett heltal genom att avlägsna decimaldelen. Om RND(1) är t.ex. 0,1 eller 0,4 är 205,5 + 0,4 = 205, men om 205,5   tilldelas 0,6 blir resultatet 206. Vi har alltså att göra med en implisiv typomvandling från realtal till heltal.

    3. PRINT CHR$(205) ger en diagonal linje från vänster till höger, och CHR$(306) ger en diagonal linje från höger till vänster. Koden i fråga ger alltså antingen \ eller / i en följd, vilket ger en labyrint.

    Detta är resultatet av koden på en Commodore 64 eller 128:

    c64

    Detta är resultatet av samma kod på en Vic 20:

    vic20

  • 16K RAM till ZX81

    Detta är mitt expansionskort som ger 16K RAM till Sinclair ZX81.

  • Gratis Instagram från Windows

    Att komma igång med Instagram från din vanliga PC (eller Mac) kräver lite mickel, men är helt gratis och fungerar utmärkt när man väl är igång. Med Instagram installerat kan du posta filer från ditt lokala filsystem, och eftersom lösningen bygger på det mycket trevliga projektet BlueStacks, ger det dig samtidigt tillgång till Google Play. Här är de 10 steg du behöver ta:

    1. Installera BlueStacks. Jag har varit med om att detta krånglar på Windows 7, men jag har installerat det på två Windows 8-maskiner helt utan problem (en HP EliteBook och en ASUS). Under installationen, välj gärna att du vill ha App store access och App notifications.

    Under första fasen kopierar installationsprogrammet för BlueStacks filerna. När detta är klart kommer en ny stapel att titta på medan runtime data laddas hem. Efter att första fasen är klar, dyker BlueStacks-ikonen upp i aktivitetsfältet.

    1

    När installationen är klar, startas BlueStacks App Player (BSAP) i fullskärmsläge. Ett tryck på F11 placerar BSAP i ett vanligt fönster.

    2. Avsluta BSAP och starta BSAP genom att dubbelklicka på Start BlueStacks på skrivbordet. Detta borde sätta BSAP i registreringsläge. Detta är nödvändigt för att Google Play ska kunna användas. Följ alla steg så att både registreringen av enheten och synkroniseringsfunktionen blir aktiverad. Aslutningsvis ser du en tom skärm med texten Select your mobile devices. Klicka Done så är du klar.

    2

    3. Klicka på sökknappen uppe till vänster. Sök reda på Instagram och installera den. Växla till My Apps, starta Instagram. Registrera ett konto om det behövs, annars, logga in med ditt befintliga instagramkonto.

    3

    4. Klicka på sökknappen igen, installera ES File Explorer.

    4

    5. Skapa en genväg till mappen C:\ProgramData\BlueStacks\UserData\SharedFolder – det är den du kan nå från BlueStacks. Placera bilden du vill publicera där.

    5

    6. När du ska posta en bild från Instagram-appen, välj att hämta den från Android-mappen /sdcard/bstfolder/BstSharedFolder. Där hittar du din bild.

    6

    På vissa system behöver du roota BlueStacks. Det är ingen konst att göra, men nedladdningen var lite omständig, eftersom sidan innehåller en download manager som är totalt hopplös. Stegen är dock tydligt förklarade på denna sida.

    Om det gick bra, följ mig gärna på Instagram!

  • Skalning av vektorgrafik på Commodore 128

    Genom kommandot SCALE kan man skala vektorgrafiken, alltså den grafik som skapas med kommandon som DRAW, CIRCLE och BOX – inte sprite-grafik eller text. När man arbetar med högupplöst grafik utan skalning är skärmen 320 pixlar bred och 200 pixlar hög. Detta program skapar en stor ellips som tar upp nästan hela skärmen.

    10 GRAPHIC 1, 1 : REM AKTIVERA HÖGUPPLÖST GRAFIK
    20 CIRCLE 1, 159, 99, 130, 80 : REM RITA EN ELLIPS ÖVER NÄSTAN HELA
    30 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
    40 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

    01

    Genom att infoga SCALE-kommandot efter GRAPHIC-kommandot påverkar man skalan på det som ritas efter anropet på SCALE. SCALE har ingen effekt om det anropas innan man gått in i grafikläget (före GRAPHIC-anropet) och påverkar det som ritas därefter. Det första argumentet som skickas till SCALE är 1 för att aktivera skalning. Det andra är den antalet virtuella pixlar du vill ha i X-led, och det tredje är antalet virtuella pixlar du vill ha i Y-led.

    Här infogar jag ett anrop på SCALE på rad 15 (efter GRAPHIC på rad 10) och anropar sedan RENUMBER för att få tillbaka jämna mellanrum mellan raderna. Även om pixlarna fortfarande är lika stora, ritas nu bilden med den virtuella upplösningen av 640 * 400 pixlar.

    10 GRAPHIC 1, 1 : REM AKTIVERA HÖGUPPLÖST GRAFIK
    20 SCALE 1, 640, 400
    30 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
    40 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
    50 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

    02

    Detta är användbart när man tänker på att flerfärgsläget innehåller väldigt breda pixlar. När flerfärgsgrafik används består skärmen (som är i 4:3-format) av 160 * 200 pixlar. Om vi kör ursprungsprogrammet, utan SCALE-anropet, i flerfärgsläge (läge 3).

    10 GRAPHIC 3, 1 : REM AKTIVERA FLERFÄRGSGRAFIK
    20 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
    30 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
    40 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

    03

    Men trots pixlarnas storlek, kan man alltså behålla den virtuella upplösningen av 320 * 200 genom att anropa SCALE. Nu blir det dock lite lustigt. SCALE kompenserar inte för pixlarnas bredd, så de virtuella 320 * 200 pixlarna får vi när vi ber om 640 * 200 pixlar.

    10 GRAPHIC 3, 1 : REM AKTIVERA FLERFÄRGSGRAFIK
    20 SCALE 1, 640, 200
    30 CIRCLE 1, 159, 99, 130, 80 : REM RITA SAMMA ELLIPS
    40 INPUT A$ : REM TRYCK PÅ ENTER FÖR ATT AVSLUTA
    50 GRAPHIC 0 : REM ÅTERGÅ TILL TEXT-LÄGET

    04

    För att stänga av skalning, anropa SCALE med argumentet 0.

  • Arcade classics

    [nggallery id=2]

  • Atari Sky Raider

    What the fuck is this? In 1978 Atari releases the arcade game Sky Driver. Insert a coin, and experience spectacular semi-3D graphics. You are controlling a bomber on an airplane and you fire away on objects on the ground. Suddenly, the “time is out” and the game is over. In the middle of all the fun, you are told to walk away or add more coins. So HOW do I get extended play? Why do you do this to me, Atari?

    sky_raider

  • TPB AFK

    Om du är en del av copyrightlobbyn eller om du av andra skäl står oförstående för tankar kring rättssäkerhet, är detta inte texten för dig.

    Innan jag såg filmen TPB AFK trodde jag att Sverige kvalificerade som bananrepublik eftersom man iscensatte rättegångar på grund av att man såg ett hot man helt enkelt inte kunde hantera. Men det är något annat är problemet.

    Själva idén om att torrents är ett nytt sätt att sprida information är inte en aspekt som vill samtalas, och själva idén att kommersiella företag, filmbolag, musikbolag eller vad som helst, kan tjäna pengar på att exploatera marknaden som den ser ut, hånas. Alltså, det som alla andra affärsidkare är förpassade till, hånar musikindustrin. Åklagaren vann, eftersom åklagaren och domaren var samma juridiska person. Domaren stämde, och dömde. Och vann. I många andra länder ska domaren vara en utomstående jurist, men inte i Sverige.

    Avgörande för domen är inte personerna bakom The Pirate Bay, utan det faktum att ny teknik kan exploateras för olaglig verksamhet, och att tillgängliggöra ny teknik var det verkliga brottet. Och sen var det den där lilla frågan om hur förluster verkligen beräknas. Mediaindustrin är den enda bransch som på allvar påstår att de har ett negativt antal anställda, och med hjälp av “copyright math” beräknar man vilket skadestånd man ska ha.

    Som upphovsman inom mjukvara och musik, skulle jag önska att jag inte hade personer som åklagare Håkan Roswall eller domare Tomas Norström på min sida. Kreativitet inom infrastruktur måste börja betraktas som en plattform och i förläningen en förutsättning för dem som producerar innehåll. Att reflexmässigt fuska inom juridiken vid minsta motgång, är ett tecken på att man inte är mogen att ta sig an branschen över huvudet taget.

    Piratkopiering är fel, men upphovsrättsmännen har gjort sig själva till ett korrupt särintresse. Forskning och framsteg är verkligen ett problem, men också ett nödvändigt sådant, eftersom frånvaron av utveckling också är ett problem, om möjligt ett ännu större. Att jaga personer som illegalt delar filer, piratkopierar eller profiterar på andras verk, borde intressera upphovsrättsinnehavarna.

    Är The Pirate Bay den första organisationen som representerar nya distributionskanaler som upphovsrättsindustrin ger sig på? Nej, samtliga kanaler som de exploaterat för att tjäna pengar, har de först motarbetat. Det är så man känner igen personer med tveksam affärsmoral.

  • Boot Hill 1977

    Boot Hill 1977

    I associate Boot Hill with cheap restaurants along country roads that I visited in the early eighties when while traveling from and to national vacation destinations. However, the game itself is excellent, especially if you consider that it came out in 1977. The idea is simple – kill your opponent with a pistol – but artwork and audio is superb. And as a kid, after spending 4-5 hours in a car reading Spiderman while the radio playing easy listening, this was great. Try it out!

  • På allmän begäran (nåja)

    På allmän begäran (nåja)

    Efter att ha slängt ihop en enkel digitaliseringskod i VB som exporterar Commodore 128-kod, kan jag nu tillgodose önskemålet som alla Commodore-användare har: En idolbild på mig!

    Detta är koden som genererades. Notera hur digitaliseraren lagrar två instruktioner per rad, och att den skapar “tända” pixlar som DRAW-instruktioner. Flera tända pixlar på raden, genereras som horisontella linjer.

    10 COLOR 1,16:COLOR 2,12:GRAPHIC 1,1
    20 DRAW 1,147,4 TO 150,4:DRAW 1,144,5 TO 152,5
    30 DRAW 1,155,5 TO 161,5:DRAW 1,142,6 TO 164,6
    40 DRAW 1,139,7 TO 166,7:DRAW 1,138,8 TO 167,8
    50 DRAW 1,136,9 TO 169,9:DRAW 1,135,10 TO 170,10
    60 DRAW 1,134,11 TO 171,11:DRAW 1,132,12 TO 172,12
    70 DRAW 1,131,13 TO 172,13:DRAW 1,130,14 TO 173,14
    80 DRAW 1,129,15 TO 174,15:DRAW 1,129,16 TO 175,16
    90 DRAW 1,128,17 TO 176,17:DRAW 1,127,18 TO 176,18
    100 DRAW 1,126,19 TO 177,19:DRAW 1,126,20 TO 178,20
    110 DRAW 1,125,21 TO 178,21:DRAW 1,125,22 TO 179,22
    120 DRAW 1,124,23 TO 159,23:DRAW 1,163,23
    130 DRAW 1,166,23 TO 180,23:DRAW 1,124,24 TO 154,24
    140 DRAW 1,170,24 TO 180,24:DRAW 1,123,25 TO 149,25
    150 DRAW 1,172,25 TO 180,25:DRAW 1,123,26 TO 148,26
    160 DRAW 1,173,26 TO 180,26:DRAW 1,123,27 TO 147,27
    170 DRAW 1,174,27 TO 180,27:DRAW 1,123,28 TO 147,28
    180 DRAW 1,175,28 TO 181,28:DRAW 1,123,29 TO 146,29
    190 DRAW 1,176,29 TO 181,29:DRAW 1,122,30 TO 147,30
    200 DRAW 1,176,30 TO 182,30:DRAW 1,122,31 TO 144,31
    210 DRAW 1,147,31:DRAW 1,177,31 TO 182,31
    220 DRAW 1,122,32 TO 144,32:DRAW 1,147,32 TO 148,32
    230 DRAW 1,176,32 TO 182,32:DRAW 1,122,33 TO 145,33
    240 DRAW 1,148,33:DRAW 1,150,33
    250 DRAW 1,177,33 TO 182,33:DRAW 1,122,34 TO 146,34
    260 DRAW 1,177,34 TO 182,34:DRAW 1,122,35 TO 146,35
    270 DRAW 1,177,35 TO 181,35:DRAW 1,122,36 TO 147,36
    280 DRAW 1,177,36 TO 181,36:DRAW 1,122,37 TO 147,37
    290 DRAW 1,177,37 TO 181,37:DRAW 1,122,38 TO 147,38
    300 DRAW 1,178,38 TO 181,38:DRAW 1,121,39 TO 149,39
    310 DRAW 1,178,39 TO 181,39:DRAW 1,121,40 TO 152,40
    320 DRAW 1,171,40:DRAW 1,178,40 TO 180,40
    330 DRAW 1,121,41 TO 153,41:DRAW 1,165,41 TO 170,41
    340 DRAW 1,178,41 TO 180,41:DRAW 1,121,42 TO 147,42
    350 DRAW 1,150,42 TO 155,42:DRAW 1,166,42 TO 167,42
    360 DRAW 1,121,43 TO 157,43:DRAW 1,166,43 TO 170,43
    370 DRAW 1,120,44 TO 158,44:DRAW 1,164,44 TO 169,44
    380 DRAW 1,173,44:DRAW 1,120,45 TO 149,45
    390 DRAW 1,152,45 TO 158,45:DRAW 1,164,45 TO 165,45
    400 DRAW 1,167,45 TO 168,45:DRAW 1,120,46 TO 149,46
    410 DRAW 1,152,46 TO 158,46:DRAW 1,164,46 TO 165,46
    420 DRAW 1,167,46 TO 168,46:DRAW 1,122,47 TO 149,47
    430 DRAW 1,151,47 TO 158,47:DRAW 1,165,47 TO 166,47
    440 DRAW 1,122,48 TO 158,48:DRAW 1,122,49 TO 159,49
    450 DRAW 1,122,50 TO 145,50:DRAW 1,150,50 TO 159,50
    460 DRAW 1,122,51 TO 140,51:DRAW 1,150,51 TO 159,51
    470 DRAW 1,122,52 TO 140,52:DRAW 1,151,52 TO 159,52
    480 DRAW 1,122,53 TO 123,53:DRAW 1,125,53 TO 140,53
    490 DRAW 1,153,53 TO 159,53:DRAW 1,122,54 TO 123,54
    500 DRAW 1,125,54 TO 141,54:DRAW 1,152,54 TO 159,54
    510 DRAW 1,122,55 TO 123,55:DRAW 1,125,55 TO 141,55
    520 DRAW 1,152,55 TO 158,55:DRAW 1,178,55
    530 DRAW 1,125,56 TO 141,56:DRAW 1,143,56
    540 DRAW 1,152,56 TO 158,56:DRAW 1,178,56 TO 179,56
    550 DRAW 1,125,57 TO 142,57:DRAW 1,152,57 TO 159,57
    560 DRAW 1,178,57:DRAW 1,124,58 TO 143,58
    570 DRAW 1,152,58 TO 154,58:DRAW 1,156,58 TO 159,58
    580 DRAW 1,178,58:DRAW 1,127,59 TO 143,59
    590 DRAW 1,153,59 TO 154,59:DRAW 1,156,59 TO 160,59
    600 DRAW 1,163,59 TO 164,59:DRAW 1,178,59
    610 DRAW 1,128,60 TO 144,60:DRAW 1,153,60 TO 159,60
    620 DRAW 1,129,61 TO 144,61:DRAW 1,153,61 TO 158,61
    630 DRAW 1,130,62 TO 144,62:DRAW 1,153,62 TO 158,62
    640 DRAW 1,131,63 TO 146,63:DRAW 1,152,63 TO 157,63
    650 DRAW 1,132,64 TO 146,64:DRAW 1,151,64 TO 157,64
    660 DRAW 1,161,64:DRAW 1,132,65 TO 156,65
    670 DRAW 1,132,66 TO 156,66:DRAW 1,133,67 TO 154,67
    680 DRAW 1,133,68 TO 160,68:DRAW 1,162,68
    690 DRAW 1,133,69 TO 147,69:DRAW 1,150,69 TO 157,69
    700 DRAW 1,134,70 TO 146,70:DRAW 1,149,70 TO 156,70
    710 DRAW 1,134,71 TO 155,71:DRAW 1,135,72 TO 155,72
    720 DRAW 1,135,73 TO 153,73:DRAW 1,136,74 TO 156,74
    730 DRAW 1,136,75 TO 156,75:DRAW 1,136,76 TO 156,76
    740 DRAW 1,136,77 TO 155,77:DRAW 1,135,78 TO 155,78
    750 DRAW 1,134,79 TO 156,79:DRAW 1,133,80 TO 155,80
    760 DRAW 1,133,81 TO 155,81:DRAW 1,132,82 TO 155,82
    770 DRAW 1,131,83 TO 143,83:DRAW 1,146,83 TO 149,83
    780 DRAW 1,131,84 TO 144,84:DRAW 1,148,84 TO 149,84
    790 DRAW 1,130,85 TO 135,85:DRAW 1,137,85 TO 144,85
    800 DRAW 1,129,86 TO 136,86:DRAW 1,138,86 TO 144,86
    810 DRAW 1,128,87 TO 137,87:DRAW 1,140,87 TO 143,87
    820 DRAW 1,173,87:DRAW 1,128,88 TO 137,88
    830 DRAW 1,141,88 TO 144,88:DRAW 1,173,88 TO 174,88
    840 DRAW 1,127,89 TO 138,89:DRAW 1,142,89 TO 144,89
    850 DRAW 1,173,89 TO 175,89:DRAW 1,126,90 TO 139,90
    860 DRAW 1,144,90 TO 145,90:DRAW 1,173,90 TO 175,90
    870 DRAW 1,126,91 TO 140,91:DRAW 1,173,91 TO 176,91
    880 DRAW 1,125,92 TO 140,92:DRAW 1,174,92 TO 178,92
    890 DRAW 1,123,93 TO 141,93:DRAW 1,174,93 TO 184,93
    900 DRAW 1,122,94 TO 142,94:DRAW 1,174,94 TO 187,94
    910 DRAW 1,119,95 TO 143,95:DRAW 1,174,95 TO 190,95
    920 DRAW 1,117,96 TO 145,96:DRAW 1,175,96 TO 192,96
    930 DRAW 1,115,97 TO 145,97:DRAW 1,176,97 TO 179,97
    940 DRAW 1,181,97 TO 195,97:DRAW 1,113,98 TO 146,98
    950 DRAW 1,176,98 TO 198,98:DRAW 1,111,99 TO 147,99
    960 DRAW 1,173,99:DRAW 1,176,99 TO 202,99
    970 DRAW 1,110,100 TO 148,100:DRAW 1,171,100 TO 173,100
    980 DRAW 1,176,100 TO 205,100:DRAW 1,108,101 TO 149,101
    990 DRAW 1,171,101 TO 173,101:DRAW 1,177,101 TO 184,101
    1000 DRAW 1,186,101 TO 204,101:DRAW 1,206,101 TO 209,101
    1010 DRAW 1,106,102 TO 149,102:DRAW 1,170,102 TO 173,102
    1020 DRAW 1,177,102 TO 184,102:DRAW 1,186,102 TO 206,102
    1030 DRAW 1,208,102 TO 210,102:DRAW 1,105,103 TO 150,103
    1040 DRAW 1,170,103 TO 173,103:DRAW 1,177,103 TO 184,103
    1050 DRAW 1,186,103 TO 211,103:DRAW 1,103,104 TO 117,104
    1060 DRAW 1,120,104 TO 151,104:DRAW 1,170,104 TO 173,104
    1070 DRAW 1,177,104 TO 185,104:DRAW 1,188,104 TO 212,104
    1080 DRAW 1,101,105 TO 121,105:DRAW 1,125,105 TO 151,105
    1090 DRAW 1,170,105 TO 173,105:DRAW 1,178,105 TO 185,105
    1100 DRAW 1,189,105 TO 212,105:DRAW 1,100,106 TO 121,106
    1110 DRAW 1,125,106 TO 151,106:DRAW 1,170,106 TO 173,106
    1120 DRAW 1,178,106 TO 186,106:DRAW 1,190,106 TO 213,106
    1130 DRAW 1,99,107 TO 112,107:DRAW 1,115,107 TO 122,107
    1140 DRAW 1,126,107 TO 152,107:DRAW 1,169,107 TO 172,107
    1150 DRAW 1,178,107 TO 186,107:DRAW 1,191,107 TO 213,107
    1160 DRAW 1,98,108 TO 113,108:DRAW 1,117,108 TO 122,108
    1170 DRAW 1,126,108 TO 153,108:DRAW 1,170,108 TO 172,108
    1180 DRAW 1,178,108 TO 189,108:DRAW 1,191,108 TO 214,108
    1190 DRAW 1,96,109 TO 110,109:DRAW 1,113,109
    1200 DRAW 1,115,109 TO 124,109:DRAW 1,127,109 TO 154,109
    1210 DRAW 1,170,109 TO 172,109:DRAW 1,178,109 TO 186,109
    1220 DRAW 1,188,109 TO 190,109:DRAW 1,192,109 TO 214,109
    1230 DRAW 1,95,110 TO 112,110:DRAW 1,116,110 TO 124,110
    1240 DRAW 1,128,110 TO 155,110:DRAW 1,169,110
    1250 DRAW 1,171,110 TO 172,110:DRAW 1,178,110 TO 187,110
    1260 DRAW 1,190,110 TO 215,110:DRAW 1,94,111 TO 112,111
    1270 DRAW 1,115,111 TO 125,111:DRAW 1,128,111 TO 155,111
    1280 DRAW 1,171,111 TO 172,111:DRAW 1,178,111 TO 188,111
    1290 DRAW 1,192,111 TO 215,111:DRAW 1,94,112 TO 124,112
    1300 DRAW 1,128,112 TO 156,112:DRAW 1,171,112 TO 172,112
    1310 DRAW 1,178,112 TO 189,112:DRAW 1,193,112 TO 215,112
    1320 DRAW 1,92,113 TO 124,113:DRAW 1,129,113 TO 157,113
    1330 DRAW 1,171,113 TO 172,113:DRAW 1,179,113 TO 190,113
    1340 DRAW 1,193,113 TO 215,113:DRAW 1,91,114 TO 125,114
    1350 DRAW 1,129,114 TO 157,114:DRAW 1,171,114
    1360 DRAW 1,179,114 TO 216,114:DRAW 1,91,115 TO 126,115
    1370 DRAW 1,129,115 TO 158,115:DRAW 1,170,115 TO 171,115
    1380 DRAW 1,179,115 TO 216,115:DRAW 1,90,116 TO 112,116
    1390 DRAW 1,114,116 TO 118,116:DRAW 1,121,116 TO 127,116
    1400 DRAW 1,130,116 TO 158,116:DRAW 1,169,116 TO 171,116
    1410 DRAW 1,179,116 TO 216,116:DRAW 1,90,117 TO 113,117
    1420 DRAW 1,116,117 TO 118,117:DRAW 1,121,117 TO 128,117
    1430 DRAW 1,130,117 TO 159,117:DRAW 1,169,117 TO 171,117
    1440 DRAW 1,179,117 TO 216,117:DRAW 1,89,118 TO 113,118
    1450 DRAW 1,117,118 TO 119,118:DRAW 1,121,118 TO 129,118
    1460 DRAW 1,131,118 TO 160,118:DRAW 1,170,118 TO 171,118
    1470 DRAW 1,179,118 TO 216,118:DRAW 1,88,119 TO 114,119
    1480 DRAW 1,122,119 TO 129,119:DRAW 1,132,119 TO 160,119
    1490 DRAW 1,170,119 TO 171,119:DRAW 1,180,119 TO 218,119
    1500 DRAW 1,88,120 TO 119,120:DRAW 1,126,120 TO 129,120
    1510 DRAW 1,133,120 TO 161,120:DRAW 1,180,120 TO 219,120
    1520 DRAW 1,88,121 TO 113,121:DRAW 1,115,121 TO 119,121
    1530 DRAW 1,127,121 TO 130,121:DRAW 1,134,121 TO 162,121
    1540 DRAW 1,180,121 TO 219,121:DRAW 1,87,122 TO 114,122
    1550 DRAW 1,116,122 TO 121,122:DRAW 1,127,122 TO 131,122
    1560 DRAW 1,135,122 TO 162,122:DRAW 1,180,122 TO 219,122
    1570 DRAW 1,87,123 TO 122,123:DRAW 1,128,123 TO 133,123
    1580 DRAW 1,137,123 TO 163,123:DRAW 1,181,123 TO 220,123
    1590 DRAW 1,87,124 TO 123,124:DRAW 1,128,124 TO 134,124
    1600 DRAW 1,138,124 TO 163,124:DRAW 1,176,124
    1610 DRAW 1,181,124 TO 221,124:DRAW 1,87,125 TO 124,125
    1620 DRAW 1,128,125 TO 137,125:DRAW 1,139,125 TO 164,125
    1630 DRAW 1,173,125 TO 177,125:DRAW 1,181,125 TO 222,125
    1640 DRAW 1,87,126 TO 125,126:DRAW 1,129,126 TO 165,126
    1650 DRAW 1,173,126 TO 177,126:DRAW 1,181,126 TO 222,126
    1660 DRAW 1,87,127 TO 126,127:DRAW 1,130,127 TO 165,127
    1670 DRAW 1,174,127 TO 178,127:DRAW 1,181,127 TO 218,127
    1680 DRAW 1,220,127 TO 222,127:DRAW 1,87,128 TO 127,128
    1690 DRAW 1,131,128 TO 166,128:DRAW 1,174,128 TO 177,128
    1700 DRAW 1,181,128 TO 222,128:DRAW 1,87,129 TO 128,129
    1710 DRAW 1,132,129 TO 166,129:DRAW 1,176,129 TO 177,129
    1720 DRAW 1,181,129 TO 222,129:DRAW 1,87,130 TO 129,130
    1730 DRAW 1,133,130 TO 166,130:DRAW 1,176,130 TO 177,130
    1740 DRAW 1,181,130 TO 222,130:DRAW 1,87,131 TO 130,131
    1750 DRAW 1,134,131 TO 167,131:DRAW 1,181,131 TO 222,131
    1760 DRAW 1,87,132 TO 131,132:DRAW 1,135,132 TO 167,132
    1770 DRAW 1,181,132 TO 222,132:DRAW 1,87,133 TO 132,133
    1780 DRAW 1,138,133 TO 168,133:DRAW 1,176,133
    1790 DRAW 1,181,133 TO 224,133:DRAW 1,87,134 TO 133,134
    1800 DRAW 1,136,134:DRAW 1,139,134 TO 168,134
    1810 DRAW 1,176,134:DRAW 1,181,134 TO 224,134
    1820 DRAW 1,87,135 TO 134,135:DRAW 1,139,135 TO 168,135
    1830 DRAW 1,181,135 TO 225,135:DRAW 1,88,136 TO 135,136
    1840 DRAW 1,140,136 TO 169,136:DRAW 1,181,136 TO 225,136
    1850 DRAW 1,88,137 TO 136,137:DRAW 1,141,137 TO 169,137
    1860 DRAW 1,181,137 TO 226,137:DRAW 1,88,138 TO 137,138
    1870 DRAW 1,142,138 TO 170,138:DRAW 1,181,138 TO 226,138
    1880 DRAW 1,88,139 TO 137,139:DRAW 1,142,139 TO 170,139
    1890 DRAW 1,182,139 TO 227,139:DRAW 1,88,140 TO 138,140
    1900 DRAW 1,142,140 TO 170,140:DRAW 1,182,140 TO 228,140
    1910 DRAW 1,89,141 TO 139,141:DRAW 1,143,141 TO 170,141
    1920 DRAW 1,182,141 TO 228,141:DRAW 1,89,142 TO 140,142
    1930 DRAW 1,143,142 TO 170,142:DRAW 1,182,142 TO 229,142
    1940 DRAW 1,89,143 TO 140,143:DRAW 1,144,143 TO 171,143
    1950 DRAW 1,182,143 TO 230,143:DRAW 1,89,144 TO 141,144
    1960 DRAW 1,144,144 TO 171,144:DRAW 1,182,144 TO 230,144
    1970 DRAW 1,89,145 TO 142,145:DRAW 1,145,145 TO 171,145
    1980 DRAW 1,182,145 TO 231,145:DRAW 1,89,146 TO 143,146
    1990 DRAW 1,146,146 TO 171,146:DRAW 1,182,146 TO 231,146
    2000 DRAW 1,90,147 TO 144,147:DRAW 1,146,147 TO 172,147
    2010 DRAW 1,182,147 TO 231,147:DRAW 1,90,148 TO 144,148
    2020 DRAW 1,147,148 TO 172,148:DRAW 1,182,148 TO 232,148
    2030 DRAW 1,90,149 TO 146,149:DRAW 1,148,149 TO 172,149
    2040 DRAW 1,182,149 TO 232,149:DRAW 1,90,150 TO 146,150
    2050 DRAW 1,148,150 TO 172,150:DRAW 1,182,150 TO 233,150
    2060 DRAW 1,90,151 TO 173,151:DRAW 1,182,151 TO 233,151
    2070 DRAW 1,90,152 TO 148,152:DRAW 1,150,152 TO 173,152
    2080 DRAW 1,183,152 TO 214,152:DRAW 1,218,152 TO 234,152
    2090 DRAW 1,90,153 TO 148,153:DRAW 1,151,153 TO 173,153
    2100 DRAW 1,183,153 TO 215,153:DRAW 1,219,153 TO 235,153
    2110 DRAW 1,91,154 TO 149,154:DRAW 1,152,154 TO 174,154
    2120 DRAW 1,183,154 TO 215,154:DRAW 1,219,154 TO 236,154
    2130 DRAW 1,91,155 TO 150,155:DRAW 1,152,155 TO 174,155
    2140 DRAW 1,183,155 TO 214,155:DRAW 1,219,155 TO 220,155
    2150 DRAW 1,222,155 TO 237,155:DRAW 1,91,156 TO 151,156
    2160 DRAW 1,153,156 TO 174,156:DRAW 1,183,156 TO 214,156
    2170 DRAW 1,219,156:DRAW 1,223,156 TO 237,156
    2180 DRAW 1,91,157 TO 151,157:DRAW 1,154,157 TO 174,157
    2190 DRAW 1,182,157 TO 213,157:DRAW 1,218,157 TO 219,157
    2200 DRAW 1,224,157 TO 237,157:DRAW 1,92,158 TO 152,158
    2210 DRAW 1,154,158 TO 175,158:DRAW 1,182,158 TO 213,158
    2220 DRAW 1,218,158 TO 219,158:DRAW 1,224,158 TO 238,158
    2230 DRAW 1,92,159 TO 153,159:DRAW 1,155,159 TO 175,159
    2240 DRAW 1,182,159 TO 213,159:DRAW 1,217,159 TO 219,159
    2250 DRAW 1,223,159 TO 238,159:DRAW 1,92,160 TO 154,160
    2260 DRAW 1,156,160 TO 175,160:DRAW 1,182,160 TO 211,160
    2270 DRAW 1,216,160 TO 218,160:DRAW 1,223,160 TO 239,160
    2280 DRAW 1,92,161 TO 155,161:DRAW 1,157,161 TO 176,161
    2290 DRAW 1,182,161 TO 211,161:DRAW 1,216,161 TO 218,161
    2300 DRAW 1,223,161 TO 239,161:DRAW 1,93,162 TO 156,162
    2310 DRAW 1,158,162 TO 176,162:DRAW 1,182,162 TO 211,162
    2320 DRAW 1,216,162 TO 218,162:DRAW 1,222,162 TO 240,162
    2330 DRAW 1,93,163 TO 176,163:DRAW 1,182,163 TO 211,163
    2340 DRAW 1,215,163 TO 217,163:DRAW 1,222,163 TO 240,163
    2350 DRAW 1,93,164 TO 176,164:DRAW 1,182,164 TO 210,164
    2360 DRAW 1,215,164 TO 216,164:DRAW 1,221,164 TO 241,164
    2370 DRAW 1,93,165 TO 176,165:DRAW 1,182,165 TO 210,165
    2380 DRAW 1,214,165 TO 216,165:DRAW 1,221,165 TO 241,165
    2390 DRAW 1,94,166 TO 177,166:DRAW 1,182,166 TO 209,166
    2400 DRAW 1,213,166 TO 216,166:DRAW 1,221,166
    2410 DRAW 1,224,166 TO 242,166:DRAW 1,94,167 TO 177,167
    2420 DRAW 1,182,167 TO 209,167:DRAW 1,213,167 TO 215,167
    2430 DRAW 1,220,167:DRAW 1,224,167 TO 243,167
    2440 DRAW 1,94,168 TO 177,168:DRAW 1,182,168 TO 209,168
    2450 DRAW 1,212,168 TO 215,168:DRAW 1,219,168
    2460 DRAW 1,224,168 TO 237,168:DRAW 1,239,168 TO 243,168
    2470 DRAW 1,95,169 TO 177,169:DRAW 1,182,169 TO 209,169
    2480 DRAW 1,211,169 TO 214,169:DRAW 1,218,169 TO 219,169
    2490 DRAW 1,223,169 TO 237,169:DRAW 1,240,169 TO 244,169
    2500 DRAW 1,96,170 TO 177,170:DRAW 1,182,170 TO 215,170
    2510 DRAW 1,217,170 TO 219,170:DRAW 1,222,170 TO 245,170
    2520 DRAW 1,96,171 TO 178,171:DRAW 1,182,171 TO 246,171
    2530 DRAW 1,97,172 TO 147,172:DRAW 1,149,172 TO 178,172
    2540 DRAW 1,182,172 TO 246,172:DRAW 1,97,173 TO 178,173
    2550 DRAW 1,182,173 TO 246,173:DRAW 1,98,174 TO 178,174
    2560 DRAW 1,182,174 TO 247,174:DRAW 1,98,175 TO 178,175
    2570 DRAW 1,182,175 TO 216,175:DRAW 1,218,175 TO 221,175
    2580 DRAW 1,224,175 TO 247,175:DRAW 1,99,176 TO 179,176
    2590 DRAW 1,182,176 TO 217,176:DRAW 1,219,176 TO 223,176
    2600 DRAW 1,226,176 TO 247,176:DRAW 1,99,177 TO 179,177
    2610 DRAW 1,183,177 TO 184,177:DRAW 1,195,177 TO 202,177
    2620 DRAW 1,204,177 TO 224,177:DRAW 1,226,177 TO 247,177
    2630 DRAW 1,99,178 TO 179,178:DRAW 1,195,178 TO 201,178
    2640 DRAW 1,205,178 TO 248,178:DRAW 1,100,179 TO 179,179
    2650 DRAW 1,195,179 TO 203,179:DRAW 1,207,179 TO 248,179
    2660 DRAW 1,100,180 TO 176,180:DRAW 1,194,180 TO 204,180
    2670 DRAW 1,208,180 TO 220,180:DRAW 1,222,180 TO 249,180
    2680 DRAW 1,101,181 TO 175,181:DRAW 1,180,181 TO 182,181
    2690 DRAW 1,195,181 TO 207,181:DRAW 1,210,181 TO 249,181
    2700 DRAW 1,101,182 TO 176,182:DRAW 1,178,182 TO 189,182
    2710 DRAW 1,196,182 TO 209,182:DRAW 1,211,182 TO 249,182
    2720 DRAW 1,102,183 TO 171,183:DRAW 1,175,183 TO 192,183
    2730 DRAW 1,196,183 TO 211,183:DRAW 1,213,183 TO 250,183
    2740 DRAW 1,102,184 TO 171,184:DRAW 1,176,184 TO 193,184
    2750 DRAW 1,197,184 TO 203,184:DRAW 1,205,184 TO 212,184
    2760 DRAW 1,214,184 TO 250,184:DRAW 1,102,185 TO 152,185
    2770 DRAW 1,154,185 TO 171,185:DRAW 1,176,185 TO 195,185
    2780 DRAW 1,198,185 TO 204,185:DRAW 1,206,185 TO 214,185
    2790 DRAW 1,216,185 TO 249,185:DRAW 1,102,186 TO 166,186
    2800 DRAW 1,169,186 TO 171,186:DRAW 1,177,186 TO 197,186
    2810 DRAW 1,199,186 TO 204,186:DRAW 1,207,186 TO 215,186
    2820 DRAW 1,219,186 TO 235,186:DRAW 1,238,186 TO 249,186
    2830 DRAW 1,102,187 TO 151,187:DRAW 1,156,187 TO 164,187
    2840 DRAW 1,169,187 TO 171,187:DRAW 1,177,187 TO 198,187
    2850 DRAW 1,201,187 TO 205,187:DRAW 1,208,187 TO 217,187
    2860 DRAW 1,221,187 TO 236,187:DRAW 1,240,187 TO 249,187
    2870 DRAW 1,102,188 TO 148,188:DRAW 1,157,188 TO 159,188
    2880 DRAW 1,167,188 TO 172,188:DRAW 1,174,188 TO 200,188
    2890 DRAW 1,203,188 TO 206,188:DRAW 1,209,188 TO 219,188
    2900 DRAW 1,222,188 TO 238,188:DRAW 1,241,188 TO 249,188
    2910 DRAW 1,103,189 TO 149,189:DRAW 1,151,189 TO 155,189
    2920 DRAW 1,165,189 TO 166,189:DRAW 1,170,189 TO 172,189
    2930 DRAW 1,174,189 TO 201,189:DRAW 1,205,189 TO 206,189
    2940 DRAW 1,210,189 TO 222,189:DRAW 1,224,189 TO 239,189
    2950 DRAW 1,242,189 TO 249,189:DRAW 1,104,190 TO 155,190
    2960 DRAW 1,170,190 TO 173,190:DRAW 1,180,190 TO 206,190
    2970 DRAW 1,211,190 TO 249,190:DRAW 1,104,191 TO 155,191
    2980 DRAW 1,170,191 TO 173,191:DRAW 1,181,191 TO 190,191
    2990 DRAW 1,193,191 TO 207,191:DRAW 1,211,191 TO 249,191
    3000 DRAW 1,104,192 TO 158,192:DRAW 1,172,192 TO 173,192
    3010 DRAW 1,182,192 TO 184,192:DRAW 1,186,192 TO 191,192
    3020 DRAW 1,194,192 TO 208,192:DRAW 1,212,192 TO 249,192
    3030 DRAW 1,104,193 TO 159,193:DRAW 1,173,193 TO 174,193
    3040 DRAW 1,181,193 TO 184,193:DRAW 1,187,193 TO 191,193
    3050 DRAW 1,196,193 TO 209,193:DRAW 1,213,193 TO 248,193
    3060 DRAW 1,104,194 TO 160,194:DRAW 1,173,194
    3070 DRAW 1,181,194 TO 185,194:DRAW 1,189,194 TO 193,194
    3080 DRAW 1,197,194 TO 210,194:DRAW 1,214,194 TO 248,194
    3090 DRAW 1,104,195 TO 162,195:DRAW 1,183,195 TO 186,195
    3100 DRAW 1,190,195 TO 195,195:DRAW 1,199,195 TO 212,195
    3110 DRAW 1,215,195 TO 248,195:DRAW 1,104,196 TO 163,196
    3120 DRAW 1,183,196 TO 187,196:DRAW 1,193,196 TO 196,196
    3130 DRAW 1,200,196 TO 213,196:DRAW 1,216,196 TO 248,196
    3140 DRAW 1,105,197 TO 165,197:DRAW 1,181,197 TO 188,197
    3150 DRAW 1,195,197 TO 197,197:DRAW 1,202,197 TO 214,197
    3160 DRAW 1,218,197 TO 248,197:DRAW 1,105,198 TO 169,198
    3170 DRAW 1,173,198:DRAW 1,182,198 TO 189,198
    3180 DRAW 1,197,198 TO 200,198:DRAW 1,203,198 TO 216,198
    3190 DRAW 1,219,198 TO 236,198:DRAW 1,238,198 TO 248,198
    3200 DRAW 1,105,199 TO 174,199:DRAW 1,182,199 TO 190,199
    3210 DRAW 1,198,199 TO 201,199:DRAW 1,205,199 TO 217,199
    3220 DRAW 1,222,199 TO 237,199:DRAW 1,240,199 TO 247,199

    Resultatet visas på bilden ovan.

  • En tre månader lång spellista

    En tre månader lång spellista

    Jag har dokumenterat vad radiostationen Rockklassiker har spelat för låtar under första kvartalet 2012. Vi pratar alltså om en tre månader lång spellista bestående av 26510 poster. Med denna information kan den som är intresserad ställa frågor och göra statistiska analyser.

    Hur stor andel av låtarna är Europe-låtar? Hur många olika låtar med Queen väljer de bland? Vilken låt spelas mest? Vilka låtar spelas bara en gång? Hur förändras valet av låtar över veckor?

    Mycket nöje!

    Du kan ladda hem spellistan i Microsoft SQL Server-format här.

  • Ozma Wars review

    Ozma Wars review

    Ozma Wars is one of those infamous time thieves from my childhood. Ozma Wars is a classical shoot’em up game like Space Invaders but with two major differences. In Ozma Wars, you don’t have lifes, you have energy. You off start by docking something that looks like a boat in space, and that gives you the energy you need until next time it shows up. The second difference is that different enemies have different movement patterns, and one aspect of the game is to know what enemies are moving in what pattern. Also, some of them have target seeking missiles.

    You might want to avoid the soundtrack, that basically consists of one loud annoying sound, but as usual, the sound effects contribute to the game.

    As in Space Invaders, enemy movement speed is very dependent on how busy the main processor is, so you may be surprised by a sudden increase of speed from one enemy when you’ve just killed another. Some videos can be found here, here and here.

    The sound is annoying, but the most annoying thing is that collision detection fails from time to time and enemies randomly doesn’t get drawn. I like the game, and these glitches adds to the excitement.

  • Up’n Down (in-game)

    Up’n Down (in-game)

    A cover version of the C64 version of the Up’n Down soundtrack. Originally written by Tony Vece.

  • Car polo

    Car polo

    Car Polo is an excellent bar game. In one player mode, you control the red car and the other three are controlled by the computer. The object is to push the yellow ball in to the red goal. The purple car is on your team whereas blue and cyan cars are in the opposing team.

    In two player mode, each player controls one car and the other two cars are computer controlled. The arcade version allowed up to four players, two in each team. This is the hardware from 1977 (image stolen from www.arcade-history.com):

    The controls are lovely and this game goes well with cheap Miller beer, cigarettes and good friends. I have the ROM image from the machine, but if anyone still have the original hardware: Yes, I’d like to come to dinner!

  • Making music in Basic 7.0 part 5

    Making music in Basic 7.0 part 5

    You can add pitch bending using the SOUND command. By itself, you cannot use envelopes, just flat sounds in any given pitch. The arguments are voice (1, 2 or 3), frequency (0 to 65535), duration (16 = one second), pitch bend direction (0 = up, 1 = down, 2 sine up and down), minimum frequency, pitch bend speed, waveform (0 = triangle, 1 = saw tooth, 2 = square, 3 = noise) and finally pulse width (if waveform is 2).

    This will make a straight beep, that will play for two seconds:

    SOUND 1, 4000, 32

    And now for something completely different, a hysterical vibrato!

    SOUND 1, 5000, 32, 2, 3000, 800, 1

    To add an envelope to the sound, you use what you know on the PLAY command, and add the SOUND command immediatly before. Make sure you trigger them on the same voice.

    Both the SOUND command and the PLAY command (in combination with the ENVELOPE command and the T synthesize control character) allows you to control the waveform that is being used. When combining them, PLAY decides, not SOUND. Type in this in your Commodore 128. You might want to reset your machine first, to set all parameters to default.

    10 SOUND 1, 5000, 32, 2, 3000, 800, 1
    20 PLAY "V1T5C"

    Cool, right? Click here to listen.

  • Shadow of the Beast

    Shadow of the Beast

    The 1989 mega hit Shadow of the Beast, a run through of the different versions.

  • Making music in Basic 7.0 part 4

    Making music in Basic 7.0 part 4

    Apart from PLAY, the commands that are available for making sounds and music are TEMPO, ENVELOPE, SOUND and FILTER.

    TEMPO lets you control playback speed. The slowest is 1 and the fastest is 255.

    ENVELOPE lets you modify the ten predefined instruments. You set the instruments using the T control character (0 to 9). The arguments are:

    – The instrument you want to overwrite (0 to 9)
    – Attack rate (0 to 15)
    – Decay rate (0 to 15)
    – Sustain level (0 to 15)
    – Release rate (0 to 15)
    – Waveform (0=triangle, 1=sawtooth, 2=square with adjustable pulse width, 3=noise, 4=ring modulation)
    – Pulse width (0 to 4095) – only relevant if waveform is set to 2.

    This program creates 5 similar instruments that differ in pulse width, and uses them in a simple riff.

    10 ENVELOPE 0,0,5,0,0,2,100
    20 ENVELOPE 1,0,5,0,0,2,300
    30 ENVELOPE 2,0,5,0,0,2,500
    40 ENVELOPE 3,0,5,0,0,2,700
    50 ENVELOPE 4,0,5,0,0,2,900
    60 TEMPO 40
    70 PLAY "V1O2Q"
    80 FOR I=1 TO 2
    90 PLAY "T0CCT1CCT2CCT3CCT4CCT3CCT2CCT1CC"
    100 NEXT

    Click here to listen.

  • Making music in Basic 7.0 part 3

    Making music in Basic 7.0 part 3

    When you use the other synthesizer control characters (O, T, U and X), they apply no matter of what voice (V) you have chosen. So when you for example use O to set the octave (0 to 6), all the following notes, regardless of voice, will be played in that octave. This example will play the notes C, D and E in voice 1, octave one. C, D E in voice 1, octave 2, and finally C (at the same time as the previous E), D and E in voice 2, octave 2.

    PLAY "V1O1 CDE O2 CDE V2 CDE"

    T (0 to 9) lets you chose from 10 predefined envelopes. The predefined envelopes emulates different instruments (0 is piano, 1 is accordion and so on). Envelopes differ in attack rate, decay rate, sustain level, release rate and waveform. This song uses a harpsichord bass (T6), a drum (T3) and some xylophone (T9).

    10 FOR I=1 TO 4
    20 PLAY "V1O2T6QCCT3O5CO2T6C"
    30 PLAY "V2O5T9CV3G"
    40 NEXT

    U (0 to 15) controls the volume, but not on the next note, but also on any playing note. This will therefore play both C notes using volume 2.

    PLAY "U15 C U2 C"

    Finally, X (0 or 1) is used to turn the frequency filter on (1) or off (0).

  • Making music in Basic 7.0 part 2

    Making music in Basic 7.0 part 2

    The synthesizer control characters (V, O, T, U and X) always take one integer argument and always affect all the rest of the notes that are played. V stands for Voice and is the key to polyphonic music. Since polyphonic music is achieved by playing notes in different voices, you will use V a lot.

    Each note will be played when the previous note is done, but if you switch voices, the next note will be played immediately (if the voice you switch to is free). This will play the C note, followed by E and G at the same time. There are three voices available: 1, 2 and 3.

    PLAY "V1 CE V2 G"

    This program gives you a nice riff:

    10 FOR A=1 TO 4
    20 PLAY "V1 CE CV2EV3G"
    30 PLAY "V1 CGCC V2EV3G"
    40 PLAY "V1CV2EV3G"
    50 NEXT

  • Making music in Basic 7.0 part 1

    Making music in Basic 7.0 part 1

    In Commodore Basic 7, music is made using the PLAY command. PLAY takes one string, and that string contains the notations that you want the Commodore 128 to play. The string “CDE” will play the note C, and then the note D and finally then note E.

    PLAY "CDE"

    Possible notes are C, D, E, F, G, A and B. R is for Rest. Rests take up time, but does not make any sound. Spaces are ignored, so you can add spaces to make your string more readable. When you add a note control character to your note, this might be of interest. There are three note control characters that you can use. Control characters operates only on the note immediately to the right, spaces ignored.

    Sharp (#) will play the note a half tone higher, flat ($) will play the note a half tone lower and period (.) will increase note duration by 50%. Since note control chars only apply to the next note, this will play 4 C notes, but only the third note will be longer.

    PLAY "CC.CC"

    The synthesizer control characters and the duration control characters do not just apply to the next note to the right, but to all preceding notes. All synthesizer control characters take numeric arguments, but none of the duration control characters take any arguments. I will get back to the synthesizer control characters, but these are the duration control characters:

    W for whole note, H for half note, Q for quarter note (default), I for eight note and S for sixteenth note. This will play two bars. The first bar will consist of two quarter notes and one half note. The next bar will consist of one half note and two quarter notes.

    PLAY "QCCHCCQCC"

    With this much knowledge, you can do Smoke on the water by Deep Purple. Something like this:

    PLAY "QC#D.FC#DI#FHF"
  • Reading sequential data from your 5.25 inch floppy

    Reading sequential data from your 5.25 inch floppy

    Continued from here.

    Once you have some sequential data in a file on your disk, you can write a program to read it back. How this is done, varies between different Commodore machines, and can be quite tricky. On the C128, it is as easy as writing the data. You have to remember the structure of the data you were writing – in my case one string, one integer and one string.

    This is a new program (clear any existing program by typing NEW), and it is assumed that you have your floppy with the data you created in the earlier post.

    Use OPEN to open a file, but this time, specify that you want to READ the sequential file TEST.DAT.

    10 OPEN 1, 8, 2, "TEST.DAT,SEQ,READ"

    Then, use INPUT# to read each stored record. Just remember the data types. PRINT# supports writing multiple records in one call, and INPUT# supports multiple reads. So instead of writing three lines, I can read three records in one line, like so:

    20 INPUT#1, A$, B, C$

    Use CLOSE to close the file.

    30 CLOSE 1

    These line will display the file content on screen:

    40 PRINT A$
    50 PRINT B
    60 PRINT C$

    And if everything is correct, you will now se this:

    ONE STRING
     5
    ANOTHER STRING

    (The commands I use are available Commodore Basic 4.0 on Commodore PET, but I run Commodore Basic 7 on a C128.)

  • Sequential data on 5.25 inch floppies

    Sequential data on 5.25 inch floppies

    If you have an actual 1571 disk drive for your Commodore 128, insert a blank disk, format it using the HEADER command. Something like this:

    HEADER "MY DISK", I44, D0

    (Formatting a disk takes a while.)

    If you are running a virtual Commodore 128 in VICE, click File, Attach disk image, Drive 8. Create a d64 image file and attach that image. To create the file, enter a desired filename, like test.d64, provide a name, click Create Image, then click Attach.

    (The commands I use are available Commodore Basic 4.0 on Commodore PET, but I run Commodore Basic 7 on a C128.)

    Your disk is now inserted and completely empty. You can check the content using the DIRECTORY command.

    As a Commodore user, you know that you sometimes have to refer to your disk drive using its drive number (the first disk drive is 0) and sometimes you have to use the device number (the first disk drive is 8). The OPEN command operates on any device, therefore a device number is required in this case. The first parameter is the logical file number (just a number that identifies the file), the second is the device number (8). The third argument is a channel number – enter 2. Then, in one single string argument, you type in the file name, the file type and the file mode. I want to create a file called TEST.DAT as a sequential file and I want to write to it, so I my string holds “TEST.DAT,SEQ,WRITE”.

    10 OPEN 1, 8, 2, "TEST.DAT,SEQ,WRITE"

    To fill your file with data, use the PRINT# command. Anything goes here. This will print one string, one integer, and then yet another string. You provide your logical file number so that PRINT# knows what file you are targeting.

    20 PRINT#1, "ONE STRING"
    30 PRINT#1, 5
    40 PRINT#1, "ANOTHER STRING"

    If you like, more data can be added in one line.
    When you are done writing, close the file using the CLOSE command. Again, provide your logical file number.

    50 CLOSE 1

    After running this program, you should have a small sequential file called TEST.DAT on your disk. If any disk error occurred, the lamp on your drive is flashing now – it shouldn’t do that.

    Continued here.

  • Vic 20 software

    Vic 20 software

    The Vic 20 is not dead yet. I just found this lovely site packed with Vic 20 games and tools. To run a game in the Vice emulator, just download the prg file (download link might be hard to find for some of the programs) and autostart it from the File menu in Vice. Happy hacking in 176 x 184 pixels!

    Vic 20 photo by Sven Petersen.

  • Plotting graphics

    Plotting graphics

    The Commodore 128 has a nice API for setting graphics mode and plotting graphics, that can be used in 40 column mode. The GRAPHIC command takes a mode (0 to 5) and a “clear screen flag”, and changes the current graphics mode. 0 is the 40 column text mode and 1 is the high resolution monochrome graphics mode. This program sets a few random pixels on the screen using the DRAW command:

    10 GRAPHIC 1, 1
    20 FOR A = 1 TO 100
    30 DRAW 1, RND(1) * 320, RND(1) * 200
    40 NEXT A

    When the program is run, the text is hidden, so to retain the text cursor, just type GRAPHIC 0 and hit Enter. If you like, you can add this to your program.

    The Commodore 64 does not provide any API for graphics, so on the C64 this task is accomplished by manipulating bits in a memory area. You can jump to graphics mode by setting the bit 6 on byte 53265 to 1 and return to text mode by setting it to 0. While plotting, you must make sure you know how to handle bit patterns. The screen area can be located at 8192 if we set a flag for this (bit 4 at byte 53272), like so:

    10 POKE 53272, PEEK(53272) OR 8

    The screen consist of 8000 bytes, so in this case from 8192 to 9191. Then, enter graphics mode:

    20 POKE 53265, PEEK(53265) OR 32

    Now we don’t have the service to get a clean color map (that is Commodore 128 luxury), so random boxes (8×8 pixels) will have strange colors. No worries, this is expected.

    Finally, these lines of code will draw a few horizontal lines in the upper left 8×8 pixel area:

    Set graphics mode

    30 POKE 8192, 255
    40 POKE 8193, 0
    50 POKE 8194, 255
    60 POKE 8195, 0
    70 POKE 8196, 255
    80 POKE 8197, 0
    90 POKE 8198, 255
    100 POKE 8199, 0

    Click to view

    When the program has run, you will not see the text cursor, but to restore everything, type:

    POKE 53272, 21
    POKE 53265, 27

    …and our horizontal lines will be gone and the text cursor is back.

    Restoring.

  • A physical C65 in action

    A physical C65 in action

    There are some preserved footage of actual Commodore 65 machines out there. This first clip demonstrates some graphics capabilities. Note that you don’t have to specify the unit number when loading from disk.

    This clip shows how to use the Commodore 65 in C64 “fast mode”.

  • Tool for interplanetary space travel

    If you are planning on doing some interplanetary space travel, this little calculator is what you need. It will tell you how much time you need to set aside for your trip, and how much time you’ll gain by using a faster ship. Only available in Swedish (because NASA aren’t planning any such trips in the near future, so I put my faith in ESA).

    Download the tool from here (requires Windows XP SP3 or later).

  • CP/M on a Commodore machine – online resources

    To get started with CP/M, you will need a Commodore 128 with a disk drive or a computer that runs Vice (X128). The disks you need can be downloaded from here. The CP/M boot disk, the additional utilities, “more CP/M additional utilities”, the Assembler utilities and Microsoft Basic 80 (two disks).

    If you run this on a physical machine, make sure to insert the boot disk, and to push in the “40/80 display” key on your computer, before turning it on. If you are running this from Vice emulator, start your machine by passing these arguments to the x128 executable (adjust the path if necessary):

    x128.exe -80 -autostart "C:\cpm\zpmsys.d64"

    This is a text only environment, but pseudo graphics can be used, and a graphics library is available as an add-on.

    The basic usage of CP/M is described in the Commodore 128 user guide, chapter 11. If you know DOS, you will probably feel rather at home. You have the concepts of programs and arguments. DIR shows the available commands. The actual Commodore extensions consist of keyboard short cuts and are described in chapter 15 of the Commodore 128 user guide.

    What I see as the biggest challenge, is inserting the correct disk. Let’s say that you want to read the content of a file. This requires the TYPE.COM file that is located on the additional utilities disk, so you must insert that disk to be able to run that command. To avoid frustration, use two disk drives – one for the CP/M disks, and one for your files.

    To start Microsoft Basic, insert the correct disk and type MBASIC. Then, watch a movie or something. After a while, your Commodore 128 will say:

    MBASIC-80 Rev. 5.21
    [CP/M Version]
    Copyright 1977-1981 (C) by Microsoft
    Created: 28-Jul-81
    34350 Bytes free
    Ok

    If you want to write programs, the MBASIC manual can be downloaded from here.

    A five minute Turbo Pascal 3.0 demo on the Commodore 128:

  • Simon’s Basic

    I happened to find this website with some great downloads for the Commodore 64. Some compilers and some interpretators, like Simon’s Basic. Simon’s Basic extended the extremely frugal Commodore Basic 2.0 that was built in the C64. It sort of turned the C64 into a Commodore 128 by providing new sets of instructions for sound, graphics and input. The complete manual can be downloaded as a PDF from here.

    The band Barcelona named an album Simon Basic as a tribute to this programming language.

  • Let’s make the screen flash!

    This program will make the screen flash on the Commodore 128, and it will also run on the Commodore 64. The background color of the screen is stored at D021 (53281), so this effect is accomplished by manipulating the value at that address, multiple times. This program cannot be written in Basic, because the Basic interpreter is too slow.

    Remember that the machine code monitor expects code in one format, and displays it in another, so what I show here, is what I actually type in. I will write my program at location 1000 (4096) in the memory. Type MONITOR to enter the machine code monitor, and type F 1000 1100 0 to create some free space.

    To begin writing code, type . directly followed by the address you want to add an instruction to, followed by the instruction and the desired parameters. This stores what you just typed in, and expects you to type in the next command, or just hit Enter to exit the edit mode.

    .1000 LDA #$01
    STA $D021
    NOP
    NOP
    NOP
    LDA #$0B
    STA $D021
    NOP
    NOP
    NOP

    (and so on…)

    Let the final command in your program be JMP $1000.

    Press Enter to exit edit mode, type X and Enter to exit the monitor. Start your program by typing SYS 4096. Your screen should now be flashing hysterically!

    On the first row, .1000 tells the Commodore 128 machine code monitor that I want my program to start at address 1000 (4096). LDA loads a value to the accumulator, and STA stores current value in the accumulator to the given memory address, D021 (53281). The specific memory address D021 controls the background color. NOP means “no operation” and is used only to make the effect less hysterical. Finally, JMP jumps to the given address, creating an infinite loop. Who needs fireworks now?

  • Positioning sprites on the Commodore 64

    The task of positioning sprites on the C64 holds one particular oddity that I want to show. To be able to position a sprite on screen, you must master binary logic on the C64, and binary logic works in the same way as on the Commodore PET, shown here. Also, you need a visible sprite. The following code does the trick. If you don’t own a Commodore 64 and don’t have an emulator, the code also works in JaC64, an on-line C64 emulator implemented as an Java Applet. However, I can’t get the cursor keys to work in JaC64, so don’t mistype anything! 😉

    10 FOR I=0 TO 62
    20 POKE 704+I, 255
    30 NEXT I
    40 POKE 2040, 11
    50 POKE 53287, 1
    60 POKE 53248, 200
    70 POKE 53249, 200
    80 POKE 53269, 1

    The Y position of the sprite is stored at D001 (53249). You have 256 possible Y positions, but the visible area of the screen is only 200 pixels high. All you need to make the sprite cycle over the screen is some iteration that copies the values 0 to 255 to the D001 address.

    The X position however, is a bit more tricky. The X coordinate is stored at D000 (53248). But we need more than 256 possible positions to be able to place the sprite on the right side on the screen. Commodore did not waste a whole byte on solving this problem. At D010 (53264), the first bit keeps track on if D000 holds a value that represent the left part of the screen, or the right part of the screen for the first sprite (sprite 0). We have eight sprites and eight available bits at D010, so the second bit keeps track on if D002 (53250) holds a value that represent the left part of the screen, or the right part of the screen for the second sprite (sprite 1), and so on. So this is what we must do to make the sprite we displayed in the above program run over the screen:

    Iterate from 0 to 255, set the value to D000 (line 10-30). Set the first bit at D010 to 1 (line 40). Iterate from 0 to 255, set the value to D000 (line 50-70). Restore the first bit at D010 to 0 (line 80). Repeat from the beginning (line 90).

    Type NEW to delete your current program.

    10 FOR I=0 TO 255
    20 POKE 53248, I
    30 NEXT
    40 POKE 53264, PEEK(53264) OR 1
    50 FOR I=0 TO 255
    60 POKE 53248, I
    70 NEXT
    80 POKE 53264, PEEK(53264) AND 254
    90 GOTO 10

    If you ran the first program, and typed in this program correctly, you should see a sprite that flies from the left to the right across your screen.

  • Sprites on the Commodore 64

    Things gets a bit tougher on the Commodore 64, because this excellent piece of hardware did not come with Basic equipped with sprite commands. Nor has it a sprite editor or a machine code monitor. However, if we have access to a Commodore 128, sprites can be edited when in C128 mode, and then used in C64 mode. If we want, we can also use the machine code monitor in C128 mode and then execute the program in C64 mode. I am going to display a sprite without using the C128 mode.

    The bit pattern at D015 gets and sets what sprites are enabled, just as it does on the Commodore 128, but on the Commodore 128 we also have Basic commands for this. This means that the first sprite (sprite 0) is activated using:

    POKE 53269, 1

    Still, you might not see anything on the screen. You can position the sprite (sprite 0) by writing the desired X coordinate in D000 and the desired Y coordinate in D001. This will position it at 100, 100:

    POKE 53248, 100
    POKE 53249, 100

    The 0, 0 position is just above and to the left of the visible area, so if it is located at its home position, the sprite is still invisible. Also, the sprite might be empty. Run this program to make the sprite (still sprite 0) totally filled with pixels and displayed in red color. Note that the first line of code (10) tells the Commodore 64 that we want to use 02C0 to 02D7 (704 to 727) for sprite 0 data.

    10 POKE 2040, 11
    20 FOR I=0 TO 62
    30 POKE 704+I, 255
    40 NEXT I
    50 POKE 53287, 2

    Your screen should now look something like this:

    When taking this further, it is nice to have a Commodore 64 memory map available.

  • Collision detection

    A nice and quick way to create two filled sprites (sprite 1 and 2) is to enter the monitor and type:

    F 0E00 0E3E FF
    F 0E3F 0E7E FF

    Of course you can fill both at once, but this the above code nicely declares the two memory areas I am using in this example. Now, let’s write a simple Basic program to fire the two sprites so that they collide now and then. This will make one sprite white and the other cyan, and fire the movements.

    10 SPRITE 1, 1, 2, 0
    20 MOVSPR 1, 100, 100
    30 MOVSPR 1, 90#1
    40 SPRITE 2, 1, 2, 0
    50 MOVSPR 2, 100, 115
    60 MOVSPR 2, 270#1

    To detect collision between the two sprites, we can use the BUMP function. BUMP(1) returns a bit pattern telling us what sprites has collided, and BUMP(2) returns a bit pattern that tells us what sprites has collided with static graphics on screen. We would expect BUMP(1) to return 3 if sprite 1 and 2 is colliding, given that no other sprites are colliding as well, because the binary number 00000011 represents the decimal number 3. And indeed. Add these two lines to your program to see what BUMP(1) returns:

    70 PRINT BUMP(1)
    80 GOTO 70

    To interrupt the program, press RunStop. If you are using the VICE emulator, that key might be mapped to the Escape key. BUMP(1) is actually just returning the bit pattern in the byte located at D01E, so BUMP(1) is equivalent to PEEK(53278).

  • Poking graphics on the C128

    The skills of using PEEK, POKE and logical operators that I write about for the Commodore PET here, can be used to create graphics on the Commodore 128, in 40-column mode. Before you begin, you might want to clear the screen using the SCNCLR command. Odd name, I know.

    The C128 has a built in sprite engine. A sprite is a 2 dimensional area with its own memory area that can be handled separately from the rest of the screen. The C128 sprite engine supports eight sprites. Use the SPRITE command to activate a sprite. Here, I have activated the first of eight sprites:

    SPRITE 1, 1, 1, 0

    The first sprite is now activated. The default position is up to the right of the screen. However, the sprite might be invisible. If there is junk data in the address space of the sprite, you will see some obscure pixels. The sprite data is located in the memory at 3584 (0E00). Each sprite is 3 bytes (or 24 pixels) wide and 21 pixels high. Each sprite consumes 63 bytes. This information is enough to clear the sprite. In the machine code monitor, use In the machine code monitor, use M 0E00 0E3E to see the sprite data. Note that the monitor displays eight bytes at a time, so it will actually display 0E00 to 0E3F. To clear the sprite, type:

    F 0E00 0E3E 0

    Leave the monitor using X. Make sure the sprite is visible by typing in SPRITE 1, 1, 1, 0 again. Now, use the POKE statement to control which pixels should be visible and which should be hidden, according to the rules I demonstrated here.

  • Accessing individual bits on a Commodore PET

    On a Commodore PET, each byte that can be read using the PEEK function, and set using the POKE statement. A byte consist of 8 bits, and represent a number between 0 and 255. This code writes the value 5 to the memory address 1020, and then reads it back. The output is of course 5.

    POKE 1024, 5
    PRINT PEEK(1024)

    The POKE statement affects all eight bits at the given address (1024), but bits can be filtered out using logical operators AND and OR. The first (from right to left) of the eight bits represents the value 1, the second bit represents 2, the third 4, the fourth 8, the fifth 16, the sixth 32, the seventh 64 and the last bit represents the value 128.

    Since the value 5 is stored at 1024, you would expect all the bits being 0 except the first and the third, since 1 + 4 equals 5. This code reads the first four bits at 1024, and the output is 1, 0, 4 and 0. 1 because the first bit (representing 1) is set, 0 because the second isn’t set, 4 because the third (representing 4) is set and 0 because the fourth isn’t set.

    PRINT PEEK(1024) AND 1 : REM Read bit 1 - (1 if set)
    PRINT PEEK(1024) AND 2 : REM Read bit 2 - (2 if set)
    PRINT PEEK(1024) AND 4 : REM Read bit 3 - (4 if set)
    PRINT PEEK(1024) AND 8 : REM Read bit 4 - (8 if set)

    Multiple bits can also be read. This code reads both the first and the third bit on the address 1024:

    PRINT PEEK(1024) AND 5

    The result will be 0 if neither is set, 1 if the first is set, 4 if the second is set and 5 if both the first and third is set. The bit pattern of the value is 00000101, so the bits that are pointed out are the first and the third (from right to left).

    Also, you can set individual bits. OR [n] turns a bit on, where [n] is the value that the bit represents. 1, 2, 4, 8, 16, 32, 64 or 128. This code turns on the last bit at 1024:

    POKE 1024, PEEK(1024) OR 128

    The bit pattern at 1024 is now 10000101. The value that is stored at 1024 is 133, because 1 + 4 + 128 equals 133. To turn the last bit (128) back to zero, use AND together with bit pattern that contains a one at all positions that you want the existing flag to remain, and 0 at the positions you want to turn bytes off. To turn the last bit from the right off, you would want a bit pattern that looks like this: 01111111. All bytes remains, but the last bit from the right is 0. The number 127 has this pattern.

    POKE 1024, PEEK(1024) OR 127

    Now, the bit pattern at 1024 is changed back from 10000101 to 00000101. The value that is stored in the byte at 1024 is now 5 again.

    What can be done with this knowledge?

  • Visit ACNE, view source

    Visit http://www.acnestudios.com/ and view the source of their web page. There you have a small challenge for a web developer.

    Thanks for the tip, Staffan!

  • Destroying pictures using the command line

    PhotoKiller.exe is a simple command line application that loads an image, manipulates it, and saves it under a new name. By manipulating the levels, and taking some other measures, the image will look like an old color photo.

    I have a picture called “image.jpg” in a folder where I also have PhotoKiller.exe. This is the original photo:

    From the command line, start PhotoKiller.exe and pass the filename of the picture as an argument to PhotoKiller.exe.

    After a few seconds, a new png file is created, called “image.jpg.destroyed.png”. This is the result :

    Download PhotoKiller.exe from here. And here are some more examples. The original image is on the left.

  • Mandelbrot

    The day before yesterday, I did a bit on Bo E. Carlsson’s book on fractals, and then yesterday, one of the masterminds behind fractal geometry, Benoît Mandelbrot, died. Mandelbrot coined the term “fractal” and gave name to the Mandelbrot set, the fractal which he described. A fractal is a self repeating geometric shape. This is what a Mandelbrot set looks like (generated using ChaosPro):

    A closer look:

    If you are using an older version of Windows, Fractint is the best fractal software.

    The C source code for Fractint is available for download from here.

  • Fractales by Bo E. Carlsson

    I found my old book on fractales from 1992 by Bo E. Carlsson, in Swedish. The book basically lists a bunch of different fractales, and explains the underlying mathematical formulas.

    The book ends with a few Basic code listings.

    A quick translation of the Julia set fractal to Visual Basic might look like this. The code is written in a Windows Forms application, so the System.Drawing namespace is imported. I also use type inference:

    Using Btmp As New Bitmap(320, 200)
       Dim S = 3 / 200
       Dim T = 3 / 200
       Dim P = 0.31
       Dim Q = 0.04
       For YY = -1.1 To 1.1 Step S
          For XX = -1.5 To 1.5 Step T
             Dim X = XX
             Dim Y = YY
             Dim K = 0.0
             Dim I = ((200 / 3) * XX) + 160
             Dim J = ((200 / 3) * YY) + 100
             Dim M = 0.0
             Do
                Btmp.SetPixel(I, J, Color.Red)
                Dim A = ((X * X) - (Y * Y)) + P
                Dim B = ((2 * X) * Y) + Q
                X = A
                Y = B
                K += 1
                M = (X * X) + (Y * Y)
                If K > 100 Then
                   Exit Do
                End If
                If Not M < 4 Then
                   I = ((200 / 3) * XX) + 160
                   J = ((200 / 3) * YY) + 100
                   Btmp.SetPixel(I, J, Color.Black)
                End If
             Loop While M < 4
          Next
       Next
       Using G As Graphics = Me.CreateGraphics()
          G.DrawImage(Btmp, 0, 9)
       End Using
    End Using
    

    The above code could be written in the click event of a button. If you think the result is slightly stiff and unromantic, remember that the original code could be written for any strange old machine, like a Commodore 128 or an Apple II.

    Thank you, Bo E. Carlsson!

  • Editing code on the Commodore 65

    The Commodore 64 and the Commodore 128 uses the same method for editing code. You press enter over a line, and that line is stored the with the index of the entered line number, overwriting any existing code on that with that index. The Commodore 65 has the same machine code monitor as the Commodore 128 (it runs more smoothly because the C65 is much faster than the C128). Also, adding and overwriting Basic code is done in the same way. Editing is probably not, but I am not sure.

    On the C128, you just had to make sure you saw the line of code on screen, move the text cursor to it, write something else on top of what is there, and save it by pressing Enter. The C65 does not allow you to fly around with the text cursor over the screen. I loved the fact that you could move the cursor to any position, but it was tricky to collect user input if the user suddenly felt the urge to move away and type something unexpected at an arbitrary location. Perhaps they were to implement some command to do this, or perhaps they planned to allow the cursor to move freely. I don’t know.

    I have found some great improvements. Here, I have added 4 lines of code. It displays three lines of text and makes a sound. I use the LIST command to display the whole Commodore Basic 10 program.

    Already on the C128 you could use arguments to list parts of the program, and change the line numbers throughout the program using the RENUMBER command. But on the C65, you can find out the line number of certain line of code using the FIND command.

    The above image shows the C65 telling me where the word HEJ can be found in my program. Also, I can use the CHANGE command to search and replace text. Let’s say I want to change the notes I want the C65 to play, I can use CHANGE to do this. The C65 asks for each search hit before changing.

    Hope to get back to the lovely world of Commodore in the future.