我正在使用ncurses制作一个小型益智游戏,允许用户点击任何箭头键来移动每个包含一个数字的盒子,所有盒子都在一个大盒子里,以升序排列数字。它是一个4x4盒子,其中一个子盒子是空白的,这样其他子盒子就可以移动。
现在,我在访问我在函数中创建的WINDOW(而不是指针(数组时遇到了一个问题,这样我就可以销毁所有子框,更改数字数组,并根据数组重新创建子框。
#include <stdio.h>
#include <ncurses.h>
#include <math.h>
#include <string.h>
#define HEIGHT 16
#define WIDTH 32
#define STARTY ((LINES - HEIGHT) / 2)
#define STARTX ((COLS - WIDTH) / 2)
#define QEXIT 81
#define qEXIT 113
WINDOW *create_win(int height, int width, int starty, int startx){
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win, 0, 0);
wrefresh(local_win);
return local_win;
};
void destroy_win(WINDOW *local_win){
wborder(local_win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh(local_win);
delwin(local_win);
};
void draw_list(WINDOW *local_win, WINDOW *num_wins, int arr[][4], int length){
for(int i=0; i < length; i++){
for(int j=0; j < length; j++){
refresh();
WINDOW *sub_win;
int height = HEIGHT / length, width = WIDTH / length, starty = STARTY + i*height, startx = STARTX + j*width;
sub_win = create_win(height, width, starty, startx);
//wprintw(stdscr, "%d |", sizeof(*sub_win));
*(num_wins + i*4+j) = *sub_win;
//wprintw(stdscr, "%d - ", i*4+j);
//overwrite(sub_win, (num_wins + i*4+j));
//memcpy(num_wins + i*4+j, sub_win, sizeof(*sub_win));
int digity = height / 2, digitx = width / 2 - 1;
if(arr[i][j])
mvwprintw(sub_win, digity, digitx, "%d ", arr[i][j]);
else
mvwprintw(sub_win, digity, digitx, "X ");
wrefresh(sub_win);
};
};
};
void destroy_list(WINDOW *num_wins){
int length = 16;
for(int i=0; i < length; i++){
wprintw(stdscr, "%d ", i);
wborder((num_wins + i), ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh((num_wins + i));
delwin((num_wins + i));
};
};
void play(){
int arr[4][4] = {1,4,15,7,8,10,2,11,14,3,6,13,12,9,5,0};
int length = 4;
WINDOW *win;
int starty, startx;
//Placement
starty = STARTY;
startx = STARTX;
printw("Press Q or q to exitn");
//printw("%d - %dn%d - %dn", LINES, COLS, HEIGHT, WIDTH);
printw("n");
refresh();
// Create original window (Maybe it is useless)
win = create_win(HEIGHT, WIDTH, starty, startx);
// Create sub windows for numbers
WINDOW sub_wins[16];
draw_list(win, sub_wins, arr, length);
refresh();
getch();
destroy_win(&sub_wins[0]);
refresh();
//for(int i=0; i < 16; i++){
// wprintw(stdscr, "%d -", sizeof(sub_wins[i]));
//destroy_win(sub_wins + i);
//};
wrefresh(win);
int ch = getch();
while(ch != QEXIT && ch != qEXIT){
switch(ch){
case KEY_UP:
destroy_win(win);
win = create_win(HEIGHT, WIDTH, --starty, startx);
//destroy_list(sub_wins);
break;
case KEY_RIGHT:
destroy_win(win);
win = create_win(HEIGHT, WIDTH, starty, ++startx);
break;
case KEY_DOWN:
destroy_win(win);
win = create_win(HEIGHT, WIDTH, ++starty, startx);
break;
case KEY_LEFT:
destroy_win(win);
win = create_win(HEIGHT, WIDTH, starty, --startx);
break;
};
ch = getch();
};
};
int main(void){
//printList(arr, length);
printf("n");
// Init ncurses
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
// Game mechanics
play();
endwin();
return 0;
};
我在代码中抛出了多个问题,还有一些部分与我的主要问题并不完全相关。很抱歉但我想主要解决关于销毁子窗口的问题。
提前谢谢。
不能将一个窗口拆分为两个窗口。如果复制窗口结构,则需要使用一个且仅使用一个实例来引用该窗口。
*(num_wins + i*4+j) = *sub_win;
给你复制一个窗口。窗口现在位于两个位置,sub_win
和num_wins
阵列中。你没有两扇窗户,你只有一扇。所以你需要选择其中一个。
if(arr[i][j])
mvwprintw(sub_win, digity, digitx, "%d ", arr[i][j]);
else
mvwprintw(sub_win, digity, digitx, "X ");
wrefresh(sub_win);
好的,那么你修改sub_win
。这意味着您制作的副本是而不是窗口。记住,只有一个窗口。由于修改了sub_win
,因此它就是窗口。那么,在修改窗口之前复制它有什么意义,那就不再是窗口了。
void destroy_list(WINDOW *num_wins){
int length = 16;
for(int i=0; i < length; i++){
wprintw(stdscr, "%d ", i);
wborder((num_wins + i), ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh((num_wins + i));
delwin((num_wins + i));
};
};
你在这里干什么?您正在操作窗口在修改之前的副本。但是您修改了它,所以该窗口不再存在。这个代码毫无意义。
窗户是唯一的东西。如果制作WINDOW
结构的副本,则可以使用任一副本来表示窗口。但你不能两者都用——只有一个窗口。您的代码同时使用这两者。这是无效的。
总之:您制作一个窗口的副本,然后修改窗口(而不是副本(。这意味着副本是您修改窗口之前的副本,因为您修改了复制的东西,所以没有存在。因此,试图访问副本是一个错误,因为它是一个已不存在的东西的副本。
这有点像这样做:
- 你拿了一张空白的纸
- 你复制它
- 你写";1〃;在原纸上
- 您试图擦除";1〃;副本上
复制后,您可以将任何一方视为原件,因为它们在点处相同。但你也不能惹对方,否则你会非常困惑。