iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Software Development

六邊形戰士程式設計系列 第 24

D24 - MMORPG事件處理問題 視覺化篇

  • 分享至 

  • xImage
  •  

為了方便後續觀察各種事件地圖造成的影響,我們今天的目標是把地圖這個物件轉換成我們方便觀察的樣子,具體轉換方法如下 :

  • 地圖的三維陣列 grid 中每一個維度分別代表 列, 欄, 格
  • 每一格可能有0到多個物件
  • 如果格子裡面沒有物件,我們印出為「_」
  • 如果格子裡面有1個物件,我們印出物件名稱,例如「紅寶」
  • 如果格子裡面有多個物件,我們把它分成兩行印,並且讓寬度遵循最長的物件名稱,例如
       煞氣a刀賊
    ___紅寶     ___
    

參考以上作法,在 src/view 中實作一個 visualize 函式

import { GridItem, Map } from "./models/map";
import { transpose } from "./utils/array";
import { getPrintLength, padEnd } from "./utils/string";

export const visualize = (data: Map) => {
  const rowToString = (row: GridItem[][]) => {
    const rowHeight =
      row
        .map((item) => item.length)
        .reduce((prev, next) => (next > prev ? next : prev), 1) + 1;
    const getItemsWidth = (items: GridItem[]) =>
      items
        .map((item) => getPrintLength(item.name))
        .reduce((prev, next) => (next > prev ? next : prev), 1);
    const result = row.map((items) => {
      const height = items.length;
      const width = getItemsWidth(items);
      const board = new Array(rowHeight)
        .fill("")
        .map((s, i) => padEnd(s, width, i == 0 ? "_" : " ")); // 空白模板
      for (let i = 0; i < height; i++) {
        board[i] = padEnd(items[i].name, width, " ");
      }
      return board;
    });

    return (
      transpose(result)
        .reverse()
        .map((items) => items.join(""))
        .join("\n") + "\n"
    );
  };
  return data.grid.map((row) => rowToString(row)).join("");
};

最後附上一些工具函式

// src\utils\array
export const transpose = <T>(matrix: T[][]) =>
  matrix[0].map((_, colIndex) => matrix.map((row) => row[colIndex]));
// src\utils\string
const isFullWidth = (char: string) => {
  const code = char.charCodeAt(0);
  return (
    (code >= 0xff01 && code <= 0xff60) ||
    (code >= 0xffe0 && code <= 0xffe6) ||
    (code >= 0x4e00 && code <= 0x9fff)
  );
};

export const getPrintLength = (str: string) =>
  Array.from(str).reduce<number>(
    (sum, next) => sum + (isFullWidth(next) ? 2 : 1),
    0
  );

export const padEnd = (str: string, width: number, fill: string) => {
  const strWidth = getPrintLength(str);
  return str + (strWidth < width ? fill.repeat(width - strWidth) : "");
};

有了這些函式我們就可以很方便的觀察地圖的狀態變化


上一篇
D23 - MMORPG事件處理問題 事件建模篇
下一篇
D25 - MMORPG事件處理問題 壅塞控制篇
系列文
六邊形戰士程式設計30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言