16b 实模式 (BIOS/DOS) 中的 13h VGA 模式的视频内存位于地址 A000:0000,您可以随意读/写。
您还需要更复杂的评分算法,因为仅跟踪“A”的数量不会告诉您,用户将“B”洒在其他区域多少(即用户只用 B 填满整个屏幕将获胜,因为A=0)。
13h VGA 模式下的视频内存操作示例(TASM 语法):
;filename: so_13h.asm
.model small
.code
start:
mov ax,13h ; ah = 0 set mode, al = 13h 320x200 256col mode
int 10h ; set gfx mode
push 0A000h
pop es ; es = A000 (video ram segment)
; fill video ram with some pattern
xor di,di
mov bp,200
lines_loop:
mov dx,64
mov ax,1010h
shade_loop:
stosw ; write 5 pixels
stosw
stosb
; modify colours to create sort of "dither" pattern
xchg al,ah
inc ah
dec dx
jnz shade_loop ; write 320 pixels with different shades
; write 200 lines
dec bp
jnz lines_loop
; read pixel back example
mov di,(13*320 + 56) ; read pixel from [x, y] = [56, 13]
mov al,es:[di]
; here AL = 16h (colour of pixel at [56, 13] position)
; wait for any key
xor ax,ax
int 16h
; restore text mode
mov ax,3 ; ah = 0, al = 3 (text mode 80x25)
int 10h
; terminate code
mov ah,4Ch
int 21h
end start
在我使用的dosbox下构建+运行:
tasm so_13h.asm
tlink /x so_13h.obj
so_13h.exe
编辑:int 10h "Read Graphics Pixel at Coordinates" 也有 BIOS 服务:
输入:
AH = 0D
BH = page number, see VIDEO PAGES
CX = column number (zero based)
DX = row number (zero based)
返回时:
AL = color of pixel read
但由于 int 调用本身的性能损失,BIOS 服务通常非常缓慢,再加上 BIOS 必须从头开始重新计算每个像素的偏移量,而例如您的“评估跟踪”可以使用一些“预期屏幕” " 缓冲区连续比较像素,重复使用前一个的偏移量到达下一个,避免过度计算。
因此,您应该尝试生成类似于我在示例中填充屏幕的方式,“批量”处理像素。
在 386 时代,即使是优化为字(两个像素)与字节(一个像素)的阅读也确实有助于真正的硬件,但这可能会使您的任务过于复杂,JFYI,即使如此细微的细节在当时也确实有所作为。
edit2:关于评分算法:
取决于你想要的分数,但你可以这样做:
- 内存中有原始的“A”缓冲区
- 计算屏幕上“A”的数量 = toPaint
- 让用户使用“B”进行绘制
- 计算屏幕上“A”的数量 = notPaint
- 从屏幕在缓冲区中的“0”上方计算“B”= overPaintL1
- 在内部缓冲区 [0,0]..[maxX-2,,maxY-2] 内重新运行,如果当前像素的右侧或底部有“A”,则将每个像素更改为“A”=这将使“A”形状更厚(可能运行两次以覆盖 +-2 或 +-3 像素)
- 在缓冲区 = overPaintL2 中计算“B”超过 0
- 让“A”再粗一次
- 在缓冲区 = overPaintL3 中计算“B”超过 0
现在最终分数可能是这样的:
score = w0 * (toPaint - notPaint) + w1 * overPaintL1 + w2 * overPaintL2 + w3 * overPaintL3
其中 w0..w3 是奖励/恶意的“权重”,w0 应该是最强的,因为这是用户绘制的完美像素数量(比如 50 ......每个错过的 A 像素也是 -50) , w1 应该是非常小的malus,例如-1(仅偏离1 个像素),w2 可能类似于-5(偏离2 个像素),w3 可能类似于-10(完全偏离形状的像素)。
因此,如果用户的形状约为 200 像素(50x50 像素的正方形),并且他过度绘制了 184 像素:notPaint = 16,并且基本上命中几乎所有地方 +-1 pix off(创建 2px 宽的正方形):overPaintL1 = 200 ,有时他会走得更远:overPaintL2 = 15,overPaintL3 = 35
那么得分 = 50 * (200-16) + -1 * 200 + -5 * 15 + -10 * 35 = 8575
(此类示例中的满分是 50*200 = 10000)。
也许你需要重新调整权重和加厚很多,但我认为这种方法最终会奏效。
编辑:关于加厚的另一个注意事项......你必须在所有方向上均匀加厚,以使“B”在每个方向上的透支成本相等,所以我原来的右/下检查无效,但是做 4 方向签入单个缓冲区也是不可能的。所以要么你需要引入第二个内部缓冲区,从一个到另一个加厚,或者先进行两次加厚,然后向前延伸并向右+底部延伸,第二次向后延伸并通过左侧+顶部延伸,或者你可以使用“绘制形状” A" 到 [-N..+N,-N..+N] 位置的内部缓冲区中,以覆盖原始设计周围的 +-N 个像素。
在源缓冲区中检测当前目标位置的 3x3 网格内的任何“A”的双缓冲区可能是最容易编码的。
我最初的描述确实只在左+上方向加厚了 A 形状,所以在底部/右侧的过度绘制会比在左侧/顶部的过度绘制更受惩罚。
嗯...最终结果证明它比直觉预期的要复杂得多,请确保您按小部分编写代码,并分别正确地调试每个部分,包括极端情况和极端输入。