News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Fill the character screen

Started by kelp7, 16:51, 28 November 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

kelp7

Hi all,


What seems like an easy thing to do is making me scratch my head quite a bit. If you have 1000 characters on the screen (in 40x25 screen mode) and wanted to fill the screen gradually with a character but in random positions until the screen was full, is there a shortcut method to this? Obviously just randomly choosing screen positions will mean quite often you are printing a character into a space that was already printed into. There should only be 1000 iterations of the print though, that's what I'm trying to achieve. Would I literally have to make a list of screen memory locations and randomize the order of the list perhaps?

robcfg

I'd look for an algorithm to randomize the numbers in an array and then draw them.

roudoudou

Or you random at the beginning then you fill remaining char close to the end to avoid slowdown. You set a limit or (clever) you make an automatic treshold.

ronaldo

You may use a simple 10-bits Galoise Linear-Shift Register, which gives you a 1023 non-repeating number sequence (1-1023), then transform each number into screen character coordinates to fill the screen. You only need 1000 numbers, but I'm sure you can live with 23 lost cycles, while you avoid having a 1024-number sequence stored in memory.

Here you have a simple example in C code. You can easily compile it with CPCtelera:


#include <cpctelera.h>
#include <stdio.h>

///////////////////////////////////////////////////////////
// Calculates next pseudo-random value using a Galois
// Linear Shift Register with taps x^10 + x^7 + 1. This
// guarantees a complete traversal of 10-bit numbers
// (values 1 to 1023) without repetition.
//
u16 g_lfsr;    // Linear Shift-Register (only last 10-bits used)
void next() {
   unsigned lastbit = g_lfsr & 1;
   
   // Shift Register by one
   g_lfsr >>= 1;           
   
   // When last bit is one, tap the register
   if (lastbit)
      g_lfsr ^= 0x0240;
}

///////////////////////////////////////////////////////////
// Prints a Character in a 40x25 screen, considering
// the screen as an array of 1000 character locations.
//  c   = character to print
//  loc = location where to print it (0-999)
//
void printLocatedChar(char c, u16 loc) {
   u8  x = 2*(loc % 40);    // This could be easily optimized, but I think this way remains clear.
   u8  y = 8*(loc / 40);
   u8* pvmem = cpct_getScreenPtr(CPCT_VMEM_START, x, y);
   cpct_drawCharM1_f(pvmem, 1, 0, c);
}

///////////////////////////////////////////////////////////
// Fills the whole screen printing 1000 characters one
// by one at different locations. It receives first location
// in array layout (1-1000) as starting point. Starting
// point must not be 0.
//  randstart = starting location (1-1000)
//
void fillScreen(u16 randStart) {
   u16 i = 1024;
   g_lfsr = randStart;

   // As LSFR will never return 0, we use numbers
   // 1 to 1000 minus 1 (0-999)
   while(--i) {
      if (g_lfsr < 1001)
         printLocatedChar('#', g_lfsr - 1);
      next();
   }
}

///////////////////////////////////////////////////////////
// Entry point
//
void main(void) {
   cpct_disableFirmware();
   fillScreen(324);     // Random start: 1 - 1024 (never 0)
   while(1);
}


Hope it helps.

KaosOverride

#4
A bit dirty but... make an array of 40x25 fill of zeroes (nearly one kilobyte) and go to X Y random pos. Store the positions at the matrix with the char. If position is allready used then recheck random pos until free one.


When you are near end then just select random lines and check for the first free column.


You have to check for timing for the pure random to only random line, so the effect looks clean. This way you don't rewrtie an allready written char but you make retries. Let's say the first 700 sre pure random XY and the final 300 are random line and search the free column...


The only random line and first column can be alternated with last column free so you don't have an allways left to right effect...


As I said, is very dirty


You can reduce the matrix to bits so each byte stores 8 positions (You just need to know It's used) and don't waste a kilobyte
KaosOverride · GitHub
MEGA Amstrad Public Amstrad folder

KaosOverride

Quote from: ronaldo on 17:53, 28 November 16
You may use a simple 10-bits Galoise Linear-Shift Register, which gives you a 1023 non-repeating number sequence (1-1023), then transform each number into screen character coordinates to fill the screen. You only need 1000 numbers, but I'm sure you can live with 23 lost cycles, while you avoid having a 1024-number sequence stored in memory.

Here you have a simple example in C code. You can easily compile it with CPCtelera:


#include <cpctelera.h>
#include <stdio.h>

///////////////////////////////////////////////////////////
// Calculates next pseudo-random value using a Galois
// Linear Shift Register with taps x^10 + x^7 + 1. This
// guarantees a complete traversal of 10-bit numbers
// (values 1 to 1023) without repetition.
//
u16 g_lfsr;    // Linear Shift-Register (only last 10-bits used)
void next() {
   unsigned lastbit = g_lfsr & 1;
   
   // Shift Register by one
   g_lfsr >>= 1;           
   
   // When last bit is one, tap the register
   if (lastbit)
      g_lfsr ^= 0x0240;
}

///////////////////////////////////////////////////////////
// Prints a Character in a 40x25 screen, considering
// the screen as an array of 1000 character locations.
//  c   = character to print
//  loc = location where to print it (0-999)
//
void printLocatedChar(char c, u16 loc) {
   u8  x = 2*(loc % 40);    // This could be easily optimized, but I think this way remains clear.
   u8  y = 8*(loc / 40);
   u8* pvmem = cpct_getScreenPtr(CPCT_VMEM_START, x, y);
   cpct_drawCharM1_f(pvmem, 1, 0, c);
}

///////////////////////////////////////////////////////////
// Fills the whole screen printing 1000 characters one
// by one at different locations. It receives first location
// in array layout (1-1000) as starting point. Starting
// point must not be 0.
//  randstart = starting location (1-1000)
//
void fillScreen(u16 randStart) {
   u16 i = 1024;
   g_lfsr = randStart;

   // As LSFR will never return 0, we use numbers
   // 1 to 1000 minus 1 (0-999)
   while(--i) {
      if (g_lfsr < 1001)
         printLocatedChar('#', g_lfsr - 1);
      next();
   }
}

///////////////////////////////////////////////////////////
// Entry point
//
void main(void) {
   cpct_disableFirmware();
   fillScreen(324);     // Random start: 1 - 1024 (never 0)
   while(1);
}


Hope it helps.


LOL!  Awesome!!
KaosOverride · GitHub
MEGA Amstrad Public Amstrad folder

SRS

Wow. Those solutions above are informatics :)

EAT THIS : brute LOCOMOTIVE BASIC (664++):

10 RANDOMIZE TIME
20 MODE 1
30 PRINT "Fill da Screen with 1000 random chars...Any key to start !"
40 CALL &BB18
50 CLS
60 i%=1000
70 u%=1
80 WHILE i%>0
90 x%=INT(RND*40)+1:y%=INT(RND*25)+1:LOCATE x%,y%
100 PEN u%:u%=u%+1:IF u%=4 THEN u%=1
110 IF COPYCHR$(#0)<=" " THEN i%=i%-1:PRINT CHR$(32+RND*220);
120 WEND
130 CALL &BB18

kelp7

Wow, really excellent responses. :) I'll try each one and see (especially see if I can convert the C code)

AMSDOS

I'm intrigued, unfortunately I don't understand the problem  :'(  I have some assembly code somewhere to draw a screen from Memory to the Screen filling the screen in a jumbled way, is this what you mean?
* Using the old Amstrad Languages :D * And create my own ;)
* Incorporating the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

#9
Quote from: SRS on 21:32, 28 November 16
Wow. Those solutions above are informatics :)

EAT THIS : brute LOCOMOTIVE BASIC (664++):
Well, you can actually do that, using a Shift-Register, in 2 lines of faster 464 basic ;)


10 mode 1:defint A-Z:c=1:RANDOMIZE TIME:s=RND*1024+1:i=1023:while i>0:i=i-1:if s<1001then p=s-1:x=p mod 40+1:y=p\40+1:locate x,y:pen c:print chr$(34+RND*220);:c=(c mod 3)+1
20 l=s and 1:s=s\2:s=s XOR &240*l:wend:call&BB18


BONUS: As it looks nice, I made up a video to show how it works :).


kelp7

Brilliant! Yes, that video shows exactly what I meant with my original post, filling the screen up in random positions but not seeming to write to the same position more than once. Now I just need to unpack that code to see how it works :)

ronaldo

@kelp7 It works exactly the same as the C code. Both are versions of the same idea: use the Galois Linear Shift Register to have a 1023 non-repeating number secuence, transform each number into screen coordinates, and print there.

Just for your reference, regarding the BASIC version:

       
  • i: 1023 item counter
  • c: Used to change the PEN colour (1-3)
  • s: 10-bits Shift Register
  • p: Temporary value to store s - 1 (so that it starts at 0)
  • x,y: screen coordinates (mode 1, 40x25)
  • l: Last bit of the Shift Register. Required to now if the Shift Register needs to be tapped. (&240 value are 2 active bits to tap the register)
I think that will help you to easily unpack the BASIC code :).

AMSDOS


Quote from: ronaldo on 11:44, 29 November 16


BONUS: As it looks nice, I made up a video to show how it works.


Yeah, so I have a routine written in Assembly which does something like that, but its not mine. It was used for drawing a Loading screen (once it had loaded), to plot a series of pixels from random points. The game it was from was Syntax from Blue Ribbon, I wouldn't had known about it had it not being on an AA Covertape.
* Using the old Amstrad Languages :D * And create my own ;)
* Incorporating the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Powered by SMFPacks Menu Editor Mod