文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

学习笔记--分布式数字华容道(下)

2024-12-02 20:36

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

我又来了。最近比较忙,导致这一篇文章拖了好久还没写,只能趁着国庆放假抽空写一写了。继前两篇文章的铺垫,我们这一篇文章就来实现分布式数字华容道的双人模式。前面的请参考学习笔记–分布式数字华容道(中)。

那现在就先开始我们今天的学习吧。

[[427574]]

正文

那我们在双人模式中呢,怎么进行同步就是一个最重要的问题了。那我们这个游戏呢,就运用分布式数据库来进行我们两台设备数据的同步了。

那要实现出一个分布式数据库的话,我们就需要先定义一些变量。

  1. private static final HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP,0x12345,"signal"); 
  2.   private static int difficulty = 3; 
  3.   private DirectionalLayout layout; 
  4.   private static int length; 
  5.   private static final int interval = 5; 
  6.   private static final int left = 32; 
  7.   private static final int top = 300; 
  8.   private static final int margin = 15; 
  9.   private static int length1; 
  10.   private static final int left1 = 32; 
  11.   private static final int top1 = 1350; 
  12.   private static final int margin1 = 10; 
  13.   private static int row_a0; 
  14.   private static int column_a0; 
  15.   private static int row_b0; 
  16.   private static int column_b0; 
  17.   private float startX; 
  18.   private float startY; 
  19.   private static Timer timer; 
  20.   private static Timer updatetimer; 
  21.   private static Timer restarttimer; 
  22.   private static Timer backtimer; 
  23.   private static Text timetext ; 
  24.   private static Text maxtext; 
  25.   private static Text wintext; 
  26.   private static int hour
  27.   private static int min
  28.   private static int sec; 
  29.   private static int msec; 
  30.   private static int restart = 0; 
  31.   private static int back = 0; 
  32.   private static int maxhour = 23; 
  33.   private static int maxmin = 59; 
  34.   private static int maxsec = 59; 
  35.   private static int maxmsec = 99; 
  36.   private static int[][] grids_a; 
  37.   private static int[][] grids_b; 
  38.   private static final String STROE_ID = "data"
  39.   private static String randomstr = ""
  40.   private static String winner = ""
  41.   private static KvManager kvManager; 
  42.   private static String strhour = ""
  43.   private static String strmin = ""
  44.   private static String strsec = ""
  45.   private static String strmsec = ""
  46.   private static String text = "暂停"
  47.   private SingleKvStore singleKvStore; 
  48.   private static Button button_moveback; 
  49.   private static Boolean isLocal; 

 接下来就是写一个分布式数据库

  1. private KvManager createManger() {//辅助类 
  2.      KvManager manager = null
  3.      try{ 
  4.          KvManagerConfig config = new KvManagerConfig(this); 
  5.          manager = KvManagerFactory.getInstance().createKvManager(config); 
  6.      } catch (KvStoreException exception) { 
  7.          HiLog.info(TAG,"ERROR"); 
  8.      } 
  9.      return manager; 
  10.  } 
  11.  
  12.  private SingleKvStore createDb(KvManager kvManager) {//数据库 
  13.      SingleKvStore kvStore = null
  14.      try{ 
  15.          Options options = new Options(); 
  16.          options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION); 
  17.          kvStore = kvManager.getKvStore(options,STROE_ID); 
  18.      } catch (KvStoreException exception) { 
  19.          HiLog.info(TAG,"ERROR"); 
  20.      } 
  21.      return kvStore; 
  22.  } 
  23.  private void subscribeDb(SingleKvStore singleKvStore) {//订阅 
  24.      class KvStoreObserveClient implements KvStoreObserver { 
  25.          @Override 
  26.          public void onChange(ChangeNotification notification) { 
  27.               
  28.          } 
  29.      } 
  30.      KvStoreObserver kvStoreObserverClient = new KvStoreObserveClient(); 
  31.      singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,kvStoreObserverClient); 
  32.  } 
  33.  
  34.  private void initDbManager() { 
  35.      kvManager = createManger(); 
  36.      singleKvStore = createDb(kvManager); 
  37.      subscribeDb(singleKvStore); 
  38.  } 

 再写两个写入数据库的函数还有读取的函数。

  1. private int queryContact_int(String key) { 
  2.      try { 
  3.          return singleKvStore.getInt(key); 
  4.      } catch (KvStoreException exception) { 
  5.          HiLog.info(TAG,"int error" + exception.getMessage()); 
  6.          return -1; 
  7.      } 
  8.  } 
  9.  private String queryContact_String(String key) { 
  10.      try { 
  11.          return singleKvStore.getString(key); 
  12.      } catch (KvStoreException exception) { 
  13.          HiLog.info(TAG,"String error" + exception.getMessage()); 
  14.          return null
  15.      } 
  16.  } 
  17.  
  18.  private void writeData_String(String key , String value) { 
  19.      if (key == null || key.isEmpty() || value == null || value.isEmpty()) 
  20.          return
  21.      singleKvStore.putString(key,value); 
  22.  } 
  23.  private void writeData_int(String key,int value) { 
  24.      if (key == null || key.isEmpty()) { 
  25.          return
  26.      } 
  27.      singleKvStore.putInt(key,value); 
  28.  } 

 那接下里我们就写一个在数据库中读取记录的函数,当开始游戏的时候,会读取该阶数中的最快的记录。

  1. public void getrecord() { 
  2.         if (queryContact_int("hour" + difficulty) != -1) 
  3.             maxhour = queryContact_int("hour" + difficulty); 
  4.         else 
  5.             maxhour = 23; 
  6.         if (queryContact_int("min" + difficulty) != -1) 
  7.             maxmin = queryContact_int("min" + difficulty); 
  8.         else 
  9.             maxmin = 59; 
  10.         if (queryContact_int("sec" + difficulty) != -1) 
  11.             maxsec = queryContact_int("sec" + difficulty); 
  12.         else 
  13.             maxsec = 59; 
  14.         if (queryContact_int("msec" + difficulty) != -1) 
  15.             maxmsec = queryContact_int("msec" + difficulty); 
  16.         else 
  17.             maxmsec = 99; 
  18.     } 

 接下来我们就开始初始化我们的数组了,然后把一台设备初始化完了的数组写到数据库中,让另外一台设备来读取数据库中的数据,再用来初始化该设备的数组。

  1. public void createGrids() { 
  2.        randomstr = ""
  3.        if (isLocal) { 
  4.            int random; 
  5.            int i = 0; 
  6.            while(i < difficulty * difficulty * 5) { 
  7.                random = (int)Math.floor(Math.random() *4 ); 
  8.                randomstr += random; 
  9.  
  10.                int temp_row = row_a0; 
  11.                int tem_column = column_a0; 
  12.  
  13.                if(random == 0){ 
  14.                    changeGrids(row_a0 - 1, column_a0); 
  15.                }else if(random == 1){ 
  16.                    changeGrids(row_a0 + 1, column_a0); 
  17.                }else if(random == 2){ 
  18.                    changeGrids(row_a0, column_a0 - 1); 
  19.                }else if(random == 3){ 
  20.                    changeGrids(row_a0, column_a0 + 1); 
  21.                } 
  22.                if(temp_row != row_a0 || tem_column != column_a0){ 
  23.                    i++; 
  24.                } 
  25.            } 
  26.            HiLog.info(TAG,randomstr); 
  27.            writeData_String("randomstr",randomstr); 
  28.        } else { 
  29.            while (true) { 
  30.                if (queryContact_String("randomstr") != null && !queryContact_String("randomstr").isEmpty()) { 
  31.                    break; 
  32.                } 
  33.            } 
  34.            randomstr = queryContact_String("randomstr"); 
  35.            HiLog.info(TAG,"randomstr: "+randomstr); 
  36.            int random; 
  37.            int i = 0; 
  38.            while(i < randomstr.length()) { 
  39.                random = randomstr.charAt(i) - '0'
  40.                if(random == 0){ 
  41.                    changeGrids(row_a0 - 1, column_a0); 
  42.                }else if(random == 1){ 
  43.                    changeGrids(row_a0 + 1, column_a0); 
  44.                }else if(random == 2){ 
  45.                    changeGrids(row_a0, column_a0 - 1); 
  46.                }else if(random == 3){ 
  47.                    changeGrids(row_a0, column_a0 + 1); 
  48.                } 
  49.                i++; 
  50.            } 
  51.            singleKvStore.putString("randomstr",""); 
  52.        } 
  53.        for (int row = 0;row < difficulty; row++) { 
  54.            for (int column = 0;column column++) { 
  55.                grids_b[row][column] = grids_a[row][column]; 
  56.            } 
  57.        } 
  58.        row_b0 = row_a0; 
  59.        column_b0 = column_a0; 
  60.        HiLog.info(TAG,"row_a0: "+ row_a0 + " column_a0: " + column_a0); 
  61.    } 

 那接下去就是把数组中的数字给画出来了。

  1. public void drawGrids() { 
  2.       layout.setLayoutConfig((new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT))); 
  3.  
  4.       Component.DrawTask task = new Component.DrawTask() { 
  5.           @Override 
  6.           public void onDraw(Component component, Canvas canvas) { 
  7.               Paint paint = new Paint(); 
  8.  
  9.               Color backcolor = new Color(Color.rgb(151,75,49)); 
  10.               paint.setColor(backcolor); 
  11.               RectFloat rect = new RectFloat(left - margin, top - margin, length * difficulty + interval * (difficulty - 1) + left + margin, length * difficulty + interval * (difficulty - 1) + top + margin); 
  12.               canvas.drawRect(rect, paint); 
  13.  
  14.               for (int row = 0; row < difficulty; row++) { 
  15.                   for (int column = 0; column < difficulty; column++) { 
  16.                       Color backgroundcolor = new Color(Color.rgb(229,188,132)); 
  17.                       paint.setColor(backgroundcolor); 
  18.                       RectFloat rectFloat = new RectFloat(left + column * (length + interval), top + row * (length + interval), left + length + column * (length + interval), top + length + row * (length + interval)); 
  19.                       canvas.drawRect(rectFloat, paint); 
  20.  
  21.                       Color numbercolor = new Color(Color.rgb(140,85,47)); 
  22.                       paint.setColor(numbercolor); 
  23.                       paint.setTextSize(length / 2); 
  24.                       if(grids_a[row][column] != 0){ 
  25.                           if(grids_a[row][column] < 10){ 
  26.                               canvas.drawText(paint,Integer.toString(grids_a[row][column]),left + column * (length + interval) + length / 12 * 5,top + row * (length + interval) + length / 3 * 2); 
  27.                           }else
  28.                               canvas.drawText(paint,Integer.toString(grids_a[row][column]),left + column * (length + interval) + length / 12 * 3,top + row * (length + interval) + length / 3 * 2); 
  29.                           } 
  30.                       } 
  31.                   } 
  32.               } 
  33.  
  34.               paint.setColor(backcolor); 
  35.               length1 = 600 / difficulty - interval; 
  36.               RectFloat rect1= new RectFloat(left1 - margin1, top1 - margin1, length1 * difficulty + interval * (difficulty - 1) + left1 + margin1, length1 * difficulty + interval * (difficulty - 1) + top1 + margin1); 
  37.               canvas.drawRect(rect1, paint); 
  38.               for (int row = 0; row < difficulty; row++) { 
  39.                   for (int column = 0; column < difficulty; column++) { 
  40.                       Color backgroundcolor1 = new Color(Color.rgb(229,188,132)); 
  41.                       paint.setColor(backgroundcolor1); 
  42.                       RectFloat rectFloat = new RectFloat(left1 + column * (length1 + interval), top1 + row * (length1 + interval), left1 + length1 + column * (length1 + interval), top1 + length1 + row * (length1 + interval)); 
  43.                       canvas.drawRect(rectFloat, paint); 
  44.  
  45.                       Color numbercolor1 = new Color(Color.rgb(140,85,47)); 
  46.                       paint.setColor(numbercolor1); 
  47.                       paint.setTextSize(length1 / 2); 
  48.                       if(grids_b[row][column] != 0){ 
  49.                           if(grids_b[row][column] < 10){ 
  50.                               canvas.drawText(paint,Integer.toString(grids_b[row][column]),left1 + column * (length1 + interval) + length1 / 12 * 5,top1 + row * (length1 + interval) + length1 / 3 * 2); 
  51.                           }else
  52.                               canvas.drawText(paint,Integer.toString(grids_b[row][column]),left1 + column * (length1 + interval) + length1 / 12 * 3,top1 + row * (length1 + interval) + length1 / 3 * 2); 
  53.                           } 
  54.                       } 
  55.                   } 
  56.               } 
  57.           } 
  58.       }; 
  59.  
  60.       layout.addDrawTask(task); 
  61.       setUIContent(layout); 
  62.   } 

 接下来就是把我们的时间还有按钮这些给画出来了。

  1. public void draw() { 
  2.       maxtext = new Text(this); 
  3.       setMaxtext(); 
  4.       maxtext.setTextSize(80); 
  5.       maxtext.setMarginTop(40); 
  6.       maxtext.setMarginLeft(140); 
  7.       layout.addComponent(maxtext); 
  8.  
  9.       timetext = new Text(this); 
  10.       timetext.setText("time: 00:00:00:00"); 
  11.       timetext.setTextSize(80); 
  12.       timetext.setMarginTop(10); 
  13.       timetext.setMarginLeft(230); 
  14.       layout.addComponent(timetext); 
  15.  
  16.       ShapeElement background = new ShapeElement(); 
  17.       background.setRgbColor(new RgbColor(138,70,50)); 
  18.       background.setCornerRadius(100); 
  19.  
  20.       Button button_again = new Button(this); 
  21.       button_again.setText("重新开始"); 
  22.       button_again.setTextAlignment(TextAlignment.CENTER); 
  23.       button_again.setTextColor(Color.WHITE); 
  24.       button_again.setTextSize(100); 
  25.       button_again.setMarginTop(1150); 
  26.       button_again.setMarginLeft(730); 
  27.       button_again.setPadding(30, 0, 30, 0); 
  28.       button_again.setBackground(background); 
  29.       button_again.setClickedListener(new Component.ClickedListener() { 
  30.           @Override 
  31.           public void onClick(Component component) { 
  32.               getrecord(); 
  33.               writeData_int("restart",1); 
  34.           } 
  35.       }); 
  36.       layout.addComponent(button_again); 
  37.  
  38.       Button button_back = new Button(this); 
  39.       button_back.setText("返回"); 
  40.       button_back.setTextAlignment(TextAlignment.CENTER); 
  41.       button_back.setTextColor(Color.WHITE); 
  42.       button_back.setTextSize(100); 
  43.       button_back.setMarginLeft(730); 
  44.       button_back.setMarginTop(90); 
  45.       button_back.setPadding(30, 0, 30, 0); 
  46.       button_back.setBackground(background); 
  47.       button_back.setClickedListener(new Component.ClickedListener() { 
  48.           @Override 
  49.           public void onClick(Component component) { 
  50.  
  51.           } 
  52.       }); 
  53.       layout.addComponent(button_back); 
  54.  
  55.       setUIContent(layout); 
  56.   } 

这就是我们的效果图,你们也可以运行查看一下是否完全一样。保证一样了之后才继续跟着一步一步慢慢走。

我们这已经算是完成了最开始同步的问题了,这算是比较重要的一个问题了,那我们接下来就要继续先完成我们的游戏功能,那在完成游戏功能之前,我们需要先写一个判断游戏是否成功的函数。

  1. public boolean gamesuccess() { 
  2.       int[][] Grids = new int[difficulty][difficulty]; 
  3.       for (int row = 0; row < difficulty; row++){ 
  4.           for (int column = 0; column < difficulty; column++){ 
  5.               Grids[row][column] = difficulty * row + column + 1; 
  6.           } 
  7.       } 
  8.       Grids[difficulty - 1][difficulty - 1] = 0; 
  9.  
  10.       for (int row = 0; row < difficulty; row++){ 
  11.           for (int column = 0; column < difficulty; column++){ 
  12.               if(grids_a[row][column] != Grids[row][column]){ 
  13.                   return false
  14.               } 
  15.           } 
  16.       } 
  17.  
  18.       return true
  19.   } 

 那接下来再写一个判断当前时间是否比最短时间要快的函数,并且写一个将当前时间写到数据库的函数。

  1. public boolean compare() { 
  2.        int nowtime = hour * 36000 + min * 6000 + sec * 100 + msec; 
  3.        int maxtime = maxhour * 36000 + maxmin * 6000 + maxsec * 100 + maxmsec; 
  4.  
  5.        return nowtime > maxtime; 
  6.    } 
  7.  
  8.    public void Write() { 
  9.        if (!compare()) { 
  10.            writeData_int("hour" + difficulty, hour); 
  11.            writeData_int("min" + difficulty, min); 
  12.            writeData_int("sec" + difficulty,sec); 
  13.            writeData_int("msec" + difficulty, msec); 
  14.        } 
  15.    } 

 那现在我们就可以来完成的我们的游戏功能了,并且我们要实现出在这一台设备上玩游戏,要将数据写入数据库,让另外一台设备来读取数据,实现数据的同步。

  1. public void swipeGrids(){ 
  2.        layout.setTouchEventListener(new Component.TouchEventListener() { 
  3.            @Override 
  4.            public boolean onTouchEvent(Component component, TouchEvent touchEvent) { 
  5.                MmiPoint point = touchEvent.getPointerScreenPosition(0); 
  6.  
  7.                switch (touchEvent.getAction()) { 
  8.                    case TouchEvent.PRIMARY_POINT_DOWN: 
  9.                        startX = point.getX(); 
  10.                        startY = point.getY(); 
  11.  
  12.                        String str_row = String.valueOf(Math.floor((startY - top - 80) / (length + interval))); 
  13.                        String str2_column = String.valueOf(Math.floor((startX - left) / (length + interval))); 
  14.                        if (!gamesuccess()) { 
  15.                            writeData_int("row" + isLocal ,str_row.charAt(0)-'0'); 
  16.                            writeData_int("column" + isLocal ,str2_column.charAt(0)-'0'); 
  17.                            changeGrids(str_row.charAt(0)-'0', str2_column.charAt(0)-'0'); 
  18.                            drawGrids(); 
  19.                            if(gamesuccess()){ 
  20.                                getrecord(); 
  21.                                setMaxtext(); 
  22.                                HiLog.info(TAG,Integer.toString(maxmsec)); 
  23.                                timer.cancel(); 
  24.                                updatetimer.cancel(); 
  25.                                if (!compare()) { 
  26.                                    maxhour = hour
  27.                                    maxmin = min
  28.                                    maxsec = sec; 
  29.                                    maxmsec = msec; 
  30.                                    Write(); 
  31.                                    setMaxtext(); 
  32.                                    setUIContent(layout); 
  33.                                } 
  34.                            } 
  35.                        } 
  36.                        break; 
  37.                } 
  38.                return true
  39.            } 
  40.        }); 
  41.    } 

 那数据同步了之后,我们是还没将数据写呈现出来。那我们现在就需要将数组b中的内容给画出来了,那我们就来写另外一个时间线程,来实现这个功能。

  1. public void update() { 
  2.       updatetimer = new Timer(); 
  3.       updatetimer.schedule(new TimerTask() { 
  4.           @Override 
  5.           public void run() { 
  6.               getUITaskDispatcher().asyncDispatch(() -> { 
  7.                   drawGrids(); 
  8.               }); 
  9.           } 
  10.       },0,500); 
  11.   } 

 那我们还需要在订阅函数中去添加一个数据同步的操作。

  1. if (queryContact_int("row" + !isLocal)!=-1 && queryContact_int("column" + !isLocal)!=-1) 
  2.            changeGrids_b(queryContact_int("row"+ !isLocal),queryContact_int("column"+ !isLocal)); 

 那我们接下来就去写一个函数让我们的时间开始动起来。

  1. public void runing(){ 
  2.      timer = new Timer(); 
  3.      timer.schedule(new TimerTask() { 
  4.          @Override 
  5.          public void run() { 
  6.              getUITaskDispatcher().asyncDispatch(()->{ 
  7.                  msec++; 
  8.                  if (msec >= 100){ 
  9.                      sec++; 
  10.                      msec = msec % 100; 
  11.                      if (sec >= 60) { 
  12.                          min++; 
  13.                          sec = sec % 60; 
  14.                          if (min >= 60) { 
  15.                              hour++; 
  16.                              min = min % 60; 
  17.                          } 
  18.                      } 
  19.                  } 
  20.                  String strhour = ""
  21.                  String strmin = ""
  22.                  String strsec = ""
  23.                  String strmsec = ""
  24.                  if (msec < 10) { 
  25.                      strmsec = "0" + Integer.toString(msec); 
  26.                  } else if (msec >= 10) { 
  27.                      strmsec = Integer.toString(msec); 
  28.                  } 
  29.                  if (sec < 10){ 
  30.                      strsec = "0" + Integer.toString(sec); 
  31.                  } else if (sec >= 10) { 
  32.                      strsec = Integer.toString(sec); 
  33.                  } 
  34.                  if (min < 10){ 
  35.                      strmin = "0" + Integer.toString(min); 
  36.                  } else if (min >= 10) { 
  37.                      strmin = Integer.toString(min); 
  38.                  } 
  39.                  if (hour < 10){ 
  40.                      strhour = "0" + Integer.toString(hour); 
  41.                  } else if (hour >= 10) { 
  42.                      strhour = Integer.toString(hour); 
  43.                  } 
  44.                  timetext.setText("time: "+ strhour +":"+strmin+":"+strsec+":"+strmsec); 
  45.              }); 
  46.          } 
  47.      },0,10); 
  48.  } 

 同样的也是需要在订阅函数中实现数据的同步 

  1. if (queryContact_int("hour"+difficulty) != -1) 
  2.                  maxhour = queryContact_int("hour"+difficulty); 
  3.              if(queryContact_int("min"+difficulty)!=-1) 
  4.                  maxmin = queryContact_int("min"+difficulty); 
  5.              if(queryContact_int("sec"+difficulty)!=-1) 
  6.                  maxsec = queryContact_int("sec"+difficulty); 
  7.              if (queryContact_int("msec"+difficulty)!=-1) 
  8.                  maxmsec = queryContact_int("msec"+difficulty); 

 那这样子我们就已经是完成了游戏功能了,接下去就来做返回按钮的点击事件吧。

  1. timer.cancel(); 
  2.                 updatetimer.cancel(); 
  3.                 terminate(); 

 那接下来我们就来写重新开始的点击事件了。那为了两台设备能同时重新开始,我就在点击重新开始的时候往数据库里面写一个信号,然后还是用一个时间线程来检测这个信号,检测到了,就重新开始游戏。

  1. public void restarting() { 
  2.       restarttimer = new Timer(); 
  3.       restarttimer.schedule(new TimerTask() { 
  4.           @Override 
  5.           public void run() { 
  6.               getUITaskDispatcher().asyncDispatch(() ->{ 
  7.                   if (restart == 1){ 
  8.                       timer.cancel(); 
  9.                       updatetimer.cancel(); 
  10.                       restart = 0; 
  11.                       initialize(); 
  12.                       runing(); 
  13.                       update(); 
  14.                   } 
  15.               }); 
  16.           } 
  17.       },0,25); 
  18.   } 

 那到这里我们的游戏也就完成了。我们也可以利用这些分布式能力来创建更多双人小游戏了。

文章相关附件可以点击下面的原文链接前往下载

https://harmonyos.51cto.com/resource/1294

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯