Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Сообщения - SMax

Страницы: [1]
1
Где? Я жду!!

2
Программирование / z88dk и блочная графика
« : 19 Октября 2026, 17:50:35 »
Возможно есть смысл открыть новую тему, но всё это крутится вокруг z88dk, языка C и т.д.

Код написан ещё в мае, но это не важно!

// zcc +zx -vn -startup=30 -clib=new -create-app minesweaper.c -o minesweaper

// Лицензия: GNU AFFERO GENERAL PUBLIC LICENSE
// Version 3, 19 November 2007
// Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>

// VER 19.10.2026 (c) Maxim Sivkov

// Реализация игры Minesweeper под z88dk
// с целью изучения языка C
// под платформу ZX Spectrum 48K.
// https://github.com/z88dk/z88dk
// Размер минного поля фиксированный 20 на 20. Мин 40.
// Нюанс. Игра также закончится, если пометить ячейку без мины.
// Не используются массивы.
// В качестве массива используется экранная память.

// Вероятно возникнет вопрос к коду, и к чему такие сложности.
// Но как оказалось, у режима -startup=30 есть много ограничений.
// И сразу ответ на вопрос, а зачем тебе режим -startup=30.
// В документации написано, что: 32x24 rom print routine, no scanf
// much smaller than other crts because the rom is used for output
// А я использую только 32x24 всегда и уменьшение размера
// компилируемого кода при использовании ROM очень критично.
// В любом случае, я получил огромное удовольствие от программирования
// на C для моего любимого ZX Spectrum 48K так же как я это делал на
// Boriel Basic и для Компонентного Паскаля/Оберона на XDevLite.
// Планирую написать тоже самое на PASTA80, но это не точно.

#include <arch/zx.h>
#include <stdio.h>
#include <stdlib.h> // for rand()
#include <input.h>
#include <sound.h>
#include <sound/bit.h>
#include <im2.h>  // для работы с прерываниями
#define ATTR_BASE 0x5800  // Адрес области атрибутов в памяти Spectrum
unsigned char curX=10,curY=10,nMines=0,fExit=0,;
uint16_t nKey;
uint16_t frames=0;

// Прототип функции (объявление)
void resetDebug(void);

void putAT(unsigned char x, unsigned char y)
{
__asm
LD  A,22     ; AT command
RST 16
ld  hl,2
add hl,sp    ; skip over return address on stack
ld  a,(hl)   ; y
RST 16
inc hl
inc hl
ld  a,(hl)   ; x
RST 16
__endasm;
}

void putINK(unsigned char colour)
{
__asm
ld  ix,2
add ix,sp
LD  A,16 ; INK command
RST 16
LD  A,(ix+0) ; colour
RST 16
__endasm;
}

void putPAPER(unsigned char colour)
{
__asm
ld  ix,2
add ix,sp
LD  A,17 ; PAPER command
RST 16
LD  A,(ix+0) ; colour
RST 16
__endasm;
}

void putFLASH(unsigned char set)
{
__asm
ld  ix,2
add ix,sp
LD  A,18 ; FLASH command
RST 16
LD  A,(ix+0) ; set
RST 16
__endasm;
}

void putBRIGHT(unsigned char set)
{
__asm
ld  ix,2
add ix,sp
LD  A,19 ; BRIGHT command
RST 16
LD  A,(ix+0) ; set
RST 16
__endasm;
}

int screenstr(unsigned char x, unsigned char y)
{
__asm
// asm_zx_cxy2saddr.asm adapted for ix
ld  ix,2
add ix,sp
ld a,(ix+0) // y coordinate
rrca
rrca
rrca
and $e0
or (ix+2)   // x coordinate
ld l,a
ld a,(ix+0) // y coordinate
and $18
or $40
ld h,a   
// zx_screenstr_callee.asm
// hl = screen address
ld      c, 96                       // number of chars to match against
ld      de, (23606)                 // use CHARS system variable to locate character set bitmap
inc     d
charloop:
ld      b, 8                        // match 8 pixel rows
push    hl
mloop:
ld      a, (de)
xor     (hl)
jr      z, cont1                    // jump if bit patterns match
inc     a
jr      nz, nomatch                 // jump if bit patterns are not inverses
cont1:
inc     de
inc     h
djnz    mloop
match:
pop     hl
ld      a, 128
sub     c
ld      l, a                        // hl = ascii char code
ld      h, b
ret
nomatch:
ld      a, b                        //Remaining rows in font left
add     a, e
ld      e, a
jp      nc, cont2
inc     d
cont2:
pop     hl
dec     c
jp      nz, charloop
ld      l, c
ld      h, c                        // return with 0 to indicate no match
scf
ret
__endasm
}

// Функция для получения seed из системного таймера
uint16_t get_seed_from_frames() {
    // Берем два байта системной переменной FRAMES по адресу 23672
    frames = *((uint16_t*)23672);
    return frames;
}

void initgame(void)
{
unsigned char s,i,j,rx,ry;
zx_border(INK_BLACK);
zx_cls(INK_WHITE | PAPER_BLACK);
putAT(0,0);
putINK(7);
putPAPER(0);
puts("\x84\x83\x83\x83\x83Maxim_Sivkov\x83\x83\x83\x83\x88");
for (i=1; i<21; i++)
{
putAT(0,i);
puts("\x8A");
putAT(1,i);
putPAPER(7);
putINK(1);
for (j=1; j<21; j++)
{
putAT(j,i);
putchar(' ');
}
putPAPER(0);
putINK(7);
putAT(21,i);
puts("\x85");
}
putAT(0,i);
puts("\x81\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x82");
putPAPER(0);
putINK(2); putAT(24,2); puts("Press"); putAT(23,3); puts("any key");
__asm__("ei"); // Включаем прерывания
in_wait_key();
nKey = in_inkey();
in_wait_nokey();
__asm__("di"); // Отключение прерываний
resetDebug();
srand(get_seed_from_frames());
putINK(7);
putPAPER(7);
for (i=1; i<41; i++)
{
rx = rand()%20+1;
ry = rand()%20+1;
s = screenstr(rx,ry);
if (s==42) // char '*'
{
i--;
}
else
{
putAT(rx,ry);
putchar('*');
}
}
putPAPER(0);
putINK(6); putAT(22,6); puts("Keys:");
putINK(7); putAT(22,7); puts("q,a,o,p -");
putINK(6); putAT(22,8); puts("Move cursr");
putINK(7); putAT(22,9); puts("space -");
putINK(6); putAT(22,10);puts("Open field");
putINK(7); putAT(22,11);puts("m -");
putINK(6); putAT(22,12);puts("Mark mine");
putINK(7); putAT(22,13);puts("x - ");
putINK(6); putAT(22,14);puts("Exit");
putINK(7); putAT(22,15);puts("d -");
putINK(6); putAT(22,16);puts("Debug Mode");
// putINK(2); putAT(24,18);puts("Press");
// putAT(23,19); puts("any key");
}

// Функция получения цвета фона
uint8_t get_paper_from_attr(uint8_t attr)
{
    return (attr >> 3) & 0x07;
}

// Чтение атрибута по координатам
uint8_t read_attr(unsigned char col, unsigned char row)
{
uint8_t *attr_ptr = (uint8_t *)(ATTR_BASE + (row * 32) + col);
return *attr_ptr;
}

// Запись атрибута по координатам
void write_attr(unsigned char col, unsigned char row, uint8_t attr) {
uint8_t *attr_ptr = (uint8_t *)(ATTR_BASE + (row * 32) + col);
*attr_ptr = attr;
}

void hideCursor(void)
{
uint8_t old_attr = read_attr(curX, curY);
uint8_t new_attr = (old_attr & 0x07) | (((old_attr >> 3) & 0x07) << 3) | (0x00 << 6) | (((old_attr >> 7) & 0x01) << 7);
write_attr(curX, curY,new_attr);
}

void showCursor(void)
{
uint8_t old_attr = read_attr(curX, curY);
uint8_t new_attr = (old_attr & 0x07) | (((old_attr >> 3) & 0x07) << 3) | (0x01 << 6) | (((old_attr >> 7) & 0x01) << 7);
write_attr(curX, curY,new_attr);
}

void moveCursor(char dx,dy)
{
if ((curX+dx)>0 && (curX+dx)<21 && (curY+dy)>0 && (curY+dy)<21)
{
bit_click();   // Короткий щелчок
hideCursor();
curX = curX+dx;
curY = curY+dy;
showCursor();
}
else
{
bit_beepfx(BEEPFX_ALARM_1);
}
}

void debug(void)
{
unsigned char s;
putPAPER(0);
putINK(7); putAT(22,0); puts("Debug:"); putINK(2); putAT(28,0); puts(" ON");
putINK(6); putAT(22,1); puts("Key:"); putINK(2); putAT(26,1); printf("%c",nKey);
putINK(6); putAT(22,2); puts("X="); putINK(2); putAT(24,2); printf("%d ",curX);
putINK(6); putAT(27,2); puts("Y="); putINK(2); putAT(29,2); printf("%d ",curY);
s = screenstr(curX,curY);
putINK(6); putAT(22,3); puts("C$=("); putINK(4); putAT(26,3); printf("%c",s); putINK(6); putAT(27,3); printf(")%d ",s);
putINK(6); putAT(22,4); puts("Mines="); putINK(7); putAT(28,4); printf("%d ",nMines);
// putINK(6); putAT(22,5); puts("f="); putINK(7); putAT(24,5); printf("%d    ",frames);
}

void resetDebug(void)
{
unsigned char i;
putINK(7); putPAPER(0); putAT(22,0); puts("Debug:"); putINK(7); putAT(28,0); puts("OFF");
putINK(0); putPAPER(0);
for (i=1; i<4; i++)
{
putAT(22,i); puts("          ");
}
}

void markMine(void)
{
if (screenstr(curX,curY)!=42)
{
fExit = 11;
}
else
{
uint8_t old_attr = read_attr(curX, curY);
uint8_t paper_attr = get_paper_from_attr(old_attr);
if (paper_attr==7)
{
nMines=nMines+1;
paper_attr=1;
}
else if (paper_attr==1)
{
nMines=nMines-1;
paper_attr=7;
}
uint8_t new_attr = (old_attr & 0x07) | ((paper_attr & 0x07) << 3) | (((old_attr >> 6) & 0x01) << 6) | (((old_attr >> 7) & 0x01) << 7);
write_attr(curX, curY,new_attr);
}
if (nMines==40)
{
fExit=7;
}
}

uint8_t checkMine(int8_t xx,yy)
{
if (screenstr(xx,yy)==42) return 1;
return 0;
}

uint8_t checkCell(int8_t x,y)
{
uint8_t nM=0;
if ((x>0) && (x<21) && (y>0) && (y<21))
{
if (screenstr(x,y)==32)
{
nM=nM+checkMine(x-1,y-1)+checkMine(x,y-1)+checkMine(x+1,y-1)+checkMine(x-1,y)+checkMine(x+1,y)+checkMine(x-1,y+1)+checkMine(x,y+1)+checkMine(x+1,y+1);
if (nM>0)
{
putINK(nM-(nM>6)*6); putPAPER(7); putAT(x,y); putchar(nM+0x30);
return 1;
}
else
{
putINK(7); putPAPER(0); putAT(x,y); putchar('#');
checkCell(x-1,y-1);
checkCell(x+1,y+1);
checkCell(x+1,y-1);
checkCell(x-1,y+1);
checkCell(x-1,y);
checkCell(x+1,y);
checkCell(x,y-1);
checkCell(x,y+1);
return 0;
}
}
}
return 2;
}

void openField(void)
{
uint8_t s=screenstr(curX,curY);
if (s==42)
{
fExit=13;
putINK(2); putPAPER(7); putAT(curX,curY); putchar('*');
}
else if (s==32)
{
checkCell(curX,curY);
showCursor();
}
}

void mainloop(void)
{
unsigned char fDebug=0;
putINK(7);
putPAPER(0);
showCursor();
while(!fExit)
{
if (fDebug) {debug();}
in_wait_key();
nKey = in_inkey();
in_wait_nokey();
switch (nKey)
{
case 'o': moveCursor(-1,0); break;
case 'p': moveCursor(1,0);  break;
case 'q': moveCursor(0,-1); break;
case 'a': moveCursor(0,1);  break;
case 'd': fDebug = 1-fDebug; if (!fDebug) {resetDebug();} break;
case 'm': markMine(); break;
case ' ': openField(); break;
case 'x': fExit=1;  break;
        break;
}
}
switch (fExit)
{
case 1: putINK(2); putAT(22,19); puts("Exit Code!"); bit_beepfx(BEEPFX_POWER_OFF); break;
case 7: putINK(2); putAT(22,19); puts("WIN!"); bit_beepfx(BEEPFX_SCORE); break;
case 11: putINK(2); putAT(22,19); puts("Miss Mine!"); bit_beepfx(BEEPFX_ALARM_2); break;
case 13: putINK(2); putAT(22,19); puts("Game OVER!"); bit_beepfx(BEEPFX_FAT_BEEP_1); break;
break;
}
}

void main(void)
{
initgame();
mainloop();
}

3
Удалось обойти ограничение режима CRT 30 с помощью вставки на ассемблере.
Пока работает.
Хотя где-то читал, что может глючить.

//zcc +zx -vn -startup=30 -clib=new -create-app test.c -o test
#include <stdio.h>
//#include <arch/zx.h>
//#include <stdlib.h>

void putAT(char x, char y)
{
__asm
LD  A,22     ; AT command
RST 16
ld  hl,2
add hl,sp    ; skip over return address on stack
ld  a,(hl)   ; y
RST 16
inc hl
inc hl
ld  a,(hl)   ; x
RST 16
__endasm;
}

void main(void)
{
char x,y;
for (y=0; y<22; y++){
for (x=0; x<32; x++){
putAT(x,y);
putchar(0x30);
}}

while(2>1) {}
}

4
Программирование / z88dk и блочная графика.
« : 27 Октября 2025, 06:34:20 »
Как говорится "Не говори гоп, пока не перепрыгнешь"

Потерял кучу времени, пока не дошло, что тут что-то не так. То выводит на экран не туда, то вообще программа вылетает с ошибкой.

//zcc +zx -vn -startup=30 -clib=sdcc_iy -create-app test.c -o test

#include <stdio.h>
#include <arch/zx.h>
#include <stdlib.h>

void printAT(unsigned char row, unsigned char col)
{
putchar(0x16); // AT
putchar(row);
putchar(col);
}

void main(void)
{
printAT(9,9); printf("9");
printAT(10,10); printf("10"); //GOTO 13;13
printAT(11,11); printf("11");
printAT(13,13); printf("13"); //Crash

while(2>1) {}
}

При вводе для команды AT 0x0A;0x0A прыгает в позицию 13;13. А если ввести команду AT 0x0D;0x0D то вообще с ошибкой вываливается.
Как я догадываюсь, это из-за того, что x0A и x0D это перевод строки и возврат каретки. Как оно перехватывается черт ногу сломит. Нужен како-то иной способ ввести команду "AT".

5
Программирование / z88dk и блочная графика.
« : 24 Октября 2025, 07:05:13 »
putchar(0x10); // Ink
putchar(0x03);
putchar(0x11); // Paper
putchar(0x00);
printf("Test");

Это то, что надо. Плюс я столкнулся с проблемой установки курсора в позицию экрана AT 0;0
С помощью кода:
putchar(0x16); // AT
putchar(0x00);
putchar(0x00);
printf("Test4");
эта проблема легко решается!

Спасибо большое, пойду дальше мучаться и страдать.
Впереди ещё определение символа и атрибута по координатам.

6
Возможно для CRT 30 стандартный для спектрума способ окрашивания текста. Я ввёл printf("\x16\x0A\x03\x10\x01\x11\x06\x13\x01Hello good Sir!"); и получил жёлтый фон и синий текст как здесь https://youtu.be/5qiXx5P6oUc?t=2443. Для \x16\x0A\x03\x10\x01\x11\x06\x13\x01 у него написано AT 22,3 INK Blue PAPER yellow FLASH 1.

Оригинально получилось. Я всякие варианты перебирал, но не догадался ввести именно так.
Что интересно, работают цвета с \x01 по \x07. На \x00 ругается. Осталось разобраться как вывести BLACK Color

7
Ну так -startup=30 не поддерживает control code, этот CRT по минимуму сделан. И про вопрос выше, также нет поддержки функции scanf(), которую вы знаете, но предполагаю, что чтение ввода всё-таки осталось, иначе был бы бесполезный CRT.

Тяжко с нуля это всё воспринимать, особенно с учётом, что в Си я полный ноль. Незнание базовых библиотек и синтаксиса напрягает.

Вот строка компиляции кода:
zcc +zx -vn -startup=30 -clib=sdcc_iy -create-app minesweaper.c -o minesweaper

И код:
#include <stdio.h>
#include <arch/zx.h>
//#include <arch/spectrum.h>
//#include <stdlib.h>

#define FLASH_ON "\x12\x31"
#define FLASH_OFF "\x12\x30"
#define BRIGHT_ON "\x13\x31"
#define BRIGHT_OFF "\x13\x30"
#define INK "\x10"
#define PAPER "\x11"
#define BLACK "\x30"
#define BLUE "\x31"
#define RED "\x32"
#define WHITE "\x37"
#define AT "\x16"
#define printInk(k)          printf("\x10%c", '0'+k)
#define printPaper(k)        printf("\x11%c", '0'+k)
#define printAt(row, col)    printf("\x16%c%c", (row)+32, (col)+32)
 
void main(void)
{
zx_cls(PAPER_WHITE);
zx_border(PAPER_BLACK);

//puts(INK BLUE); //not work
//zx_colour(112); //not work
//zx_colour(PAPER_BLACK|INK_WHITE); //not work
//printInk(1); //not work
//printPaper(1); //not work
//printAt(1,1); //not work

printf("\x8B\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x87\n");
for (int i = 1; i < 20; i++) {
printf("\x8A                    \x85\n");
}
printf("\x8E\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8D\n\n");
}

Готов к любой идее как победить проблему. Даже если идея безумная.

8
Программирование / z88dk и блочная графика.
« : 22 Октября 2025, 12:32:55 »
Теперь другая проблема появилась. Не могу изменить цвет
коды для INK, PAPER перестали работать.

puts("\x10\x31");
Говорит Invalid Colour

Прям беда какая-то.

9
Программирование / z88dk и блочная графика.
« : 21 Октября 2025, 22:42:56 »
Про это описано в ZXSpectrumZSDCCnewlib_02_HelloWorld.md

#### -startup=30 (crt30)

32x24 rom print routine, no scanf
much smaller than other crts because the rom is used for output

Я не телепат, как понять, что это то что мне надо?!

Ну хоть что-то!

На самом деле я уже счастлив, не надо использовать костыли!
Моя игра чисто текстовая (ZX Spectrum 48K) и каждый байт имеет значение.

/*
 * zcc +zx -vn -startup=30 -clib=sdcc_iy block.c -o block -create-app
 */
#include <stdio.h>
void main(void)
{
printf("\x8B\x83\x7fMaxim_Sivkov_2025\x83\x87\n");
for (int i = 1; i < 19; i++) {
printf("\x8A                    \x85\n");
}
printf("\x8E\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8C\x8D");
}


10
Программирование / z88dk и блочная графика.
« : 21 Октября 2025, 18:48:56 »
Я тоже подумал про UDG, хотя это ненормально, если уже есть готовые символы в ZX Spectrum.
Даже уже начал рисовать эти символы. А потом просто написал вопрос на форуме www.z88dk.org
https://www.z88dk.org/forum/viewtopic.php?t=12088

И мне ответили!
Работает!

/*
 * zcc +zx -vn -startup=30 -clib=sdcc_iy block.c -o block -create-app
 */

#include <stdio.h>

void main(void)
{
  for( uint8_t i=0x80; i <= 0x8F; i++ )
  {
    printf("0x%02X = %c\n", i, i);
  }
}

11
Программирование / z88dk и блочная графика.
« : 21 Октября 2025, 14:02:11 »
Стандартный шрифт в роме и кодировка (набор символов) такая https://en.wikipedia.org/wiki/ZX80_character_set. Можно определить свой шрифт https://github.com/z88dk/z88dk/wiki/Classic-GenericConsole#defining-a-custom-font, пример кода https://github.com/z88dk/z88dk/blob/2e38490f409973d45e8af4844bd2e58f4ec21e28/examples/spectrum/fontexample.c.
UPD: Я дал пример кода для ZX Spectrum, а не ZX80.

Да, я что-то ошибся. Мне надо для ZX Spectrum.
По ссылкам пробежался. Не совсем то что надо, но всё равно спасибо большое. Пригодится. Особенно fontexample.c
Хотелось бы чтобы просто набрал что-то вроде printf("\x8B\x83\x87\n"); и не заморачиваться с костылями.

12
Программирование / z88dk и блочная графика
« : 21 Октября 2025, 09:48:56 »
Делаю игрушку на C z88dk под zx80.
Никак не могу победить блочную графику, выводит пустые строки и всё. Коды с 0x80 по 0x8F. Уже по всякому изгалялся, никак не выводятся.
Подскажите как блочную графику вывести на экран?

#include <stdio.h>

void main(void) {
    int i;
   
    printf("System character set test:\n");
    printf("==========================\n");
   
    // Тест стандартных ASCII символов
    printf("ASCII (32-127): ");
    for(i = 32; i < 127; i++) {
        putchar(i);
    }
    printf("\n\n");
   
    // Тест символов блочной графики
    printf("Block graphics (128-143):\n");
    for(i = 128; i <= 143; i++) {
        printf("Code %3d: [%c]\n", i, (char)i);
    }
   
    // Тест альтернативных кодов
    printf("\nAlternative codes (176-223):\n");
    for(i = 176; i <= 223; i++) {
        printf("%c", (char)i);
    }
    printf("\n");
}

zcc +zx -lm -create-app -clib=sdcc_iy -o blocks blocks.c

Страницы: [1]