正六邊形棋盤的思路

image.png

這是一個正六邊形的棋盤愧杯,里面的格子都是由正三角形組成的
棋子也是由正三角形組成的,棋子要落在棋盤上,就要知道棋子的位置
研究的問題是朱沃,怎么去描述棋子的位置
經(jīng)過數(shù)學(xué)大神點播后,有了一點想法茅诱,分享一個思路

化簡化簡

  1. 格子編號
    因為棋子和棋盤都是由格子組成的逗物,想了半天,我覺得給格子編號會比較方便
  2. 棋盤分區(qū)
    正六邊形其實可以看做是6塊三角形組成的瑟俭,在平面直角坐標(biāo)系中按照原點旋轉(zhuǎn)是有公式的
    x1=cos(angle)x-sin(angle)y;
    y1=cos(angle)y+sin(angle)x;
    那么這個正六邊形翎卓,就可以看作由1個三角形旋轉(zhuǎn)不同角度獲得的
    給棋盤分為6個區(qū),那么研究的問題就變成了一個正三角形
  3. 建立坐標(biāo)系
    選了一個自己算著舒服的三角形建立坐標(biāo)系


    image.png
  4. 分層編號摆寄,尋找規(guī)律


    image.png
  • 每一層的Y軸坐標(biāo)相差√3/2
  • 每個編號的X軸坐標(biāo)相差1/2
  • 唯一不同的是編號3是朝上的三角形失暴,而編號1坯门,2,4是朝下的三角形逗扒,但是通過分層可以發(fā)現(xiàn)古戴,每層奇數(shù)號的三角形是朝下的,偶數(shù)號的三角形是朝上的
  • 而且朝上的三角形與朝下的三角形,他們的Y軸坐標(biāo)也是加減√3/2矩肩,X軸不變(見綠色三角形)

代碼實現(xiàn)

let baseAreas = 6
let baseIds = 81
const G3 = Math.sqrt(3)
// 把所有三角都看作是1,1的三角變換而來,那么保存一個1,1三角的坐標(biāo)
const defaultTri = [
    [0, 0],
    [1 / 2, G3 / 2],
    [-1 / 2, G3 / 2],
]
// 根據(jù)area和id獲取三角形3個頂點坐標(biāo)
function getVertex(id) {
    const [tier, index] = getTier(id)
    // 根據(jù)11變換
    let coord = transform(tier, index)
    // index如果是偶數(shù),y軸坐標(biāo)需要變換
    if (index % 2 === 0) {
        coord = indexTransformY(coord)
    }
    return coord
}

// 根據(jù)id獲取在area中的層數(shù)與該層第幾個
function getTier(id) {
    const tier = Math.ceil(Math.sqrt(id))
    // 減去上一層的總數(shù)
    const index = id - Math.pow(tier - 1, 2)
    return [tier, index]
}

function transform(tier, index) {
    // X=(tier-index)*1/2
    // y=(tier-1)*G3/2
    return defaultTri.map(([x, y]) => [x + (tier - index) * 1 / 2, y + (tier - 1) * G3 / 2])
}

function indexTransformY([
    [x1, y1],
    [x2, y2],
    [x3, y3]
]) {
    return [
        [x1, y1 + G3 / 2],
        [x2, y2 - G3 / 2],
        [x3, y3 - G3 / 2],
    ]
}

/* 
    變換的每個area旋轉(zhuǎn)60°
    x1=cos(angle)*x-sin(angle)*y;
    y1=cos(angle)*y+sin(angle)*x;
*/
function rotate(area, coord) {
    const arg = (area - 1) * 60 * 2 * Math.PI / 360
    return coord.map(([x, y]) => [
        Math.cos(arg) * x - Math.sin(arg) * y,
        Math.cos(arg) * y + Math.sin(arg) * x
    ])
}
  1. 主方法是getVertexrotate现恼,getVertex負(fù)責(zé)根據(jù)編號獲取三角形的3個頂點坐標(biāo),rotate負(fù)責(zé)根據(jù)分區(qū)旋轉(zhuǎn)這個坐標(biāo)
  2. getTier根據(jù)編號獲取層數(shù)
  3. transform 根據(jù)編號規(guī)律(層以及層內(nèi)編號)獲得三角形頂點坐標(biāo)
  4. indexTransformY根據(jù)本層編號奇偶去做Y軸變換
    通過拆分成幾個小問題就比較清晰拉~去實現(xiàn)每一個小問題的function就可以了

驗證

sanjiao.gif

附上一個比較直觀的畫圖方法

// 畫圖驗證
window.onload = function() {
    btn.addEventListener('click', () => {
        // 獲取area
        let area = document.getElementById('area').value
        let id = document.getElementById('id').value
        tri = [area, id]
        draw()
    })
    canvas.addEventListener('mousewheel', ({
        deltaY
    }) => {
        if (deltaY < 0) {
            zoom = zoom + 2
        } else {
            zoom = zoom - 2 < 0 ? 2 : zoom - 2
        }
        draw()
    })
    canvas.addEventListener('mousedown', mouseDown)
    draw()
}

function mouseDown() {
    window.addEventListener('mousemove', mouseMove)
    window.addEventListener('mouseup', mouseUp)
}

function mouseUp() {
    window.removeEventListener('mousemove', mouseMove)
    window.removeEventListener('mouseup', mouseUp)
}

function mouseMove({
    movementX,
    movementY
}) {
    origin[0]=origin[0] + movementX
    origin[1]=origin[1] + movementY
    draw()
}


board = [] // 棋盤
tri = [] // 三角

for (let i = 1; i <= baseAreas; i++) {
    for (let j = 1; j <= baseIds; j++) {
        board.push(rotate(i, getVertex(j)))
    }
}

let zoom = 30
const origin = [0, 0]

function draw() {
    drawBoard()
    drawTarget()
}

function drawBoard() {
    // 畫棋盤
    const {
        clientWidth: width,
        clientHeight: height
    } = canvas

    let oX = width / 2
    let oY = height / 2
    const ctx = canvas.getContext('2d')
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, width, height)
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#000';
    const [dx, dy] = origin
    board.forEach(([
        [x1, y1],
        [x2, y2],
        [x3, y3]
    ]) => {
        ctx.beginPath()
        // canvas y軸取反
        y1 = -y1
        y2 = -y2
        y3 = -y3
        ctx.moveTo(x1 * zoom + oX + dx, y1 * zoom + oY + dy)
        ctx.lineTo(x2 * zoom + oX + dx, y2 * zoom + oY + dy)
        ctx.lineTo(x3 * zoom + oX + dx, y3 * zoom + oY + dy)
        ctx.closePath()
        ctx.stroke();
    })
}

function drawTarget() {
    const {
        clientWidth: width,
        clientHeight: height
    } = canvas

    let oX = width / 2
    let oY = height / 2
    const ctx = canvas.getContext('2d')

    const [dx, dy] = origin
    const [area, id] = tri

    if (area && id) {
        let [
            [x1, y1],
            [x2, y2],
            [x3, y3]
        ] = rotate(area, getVertex(id))
        ctx.lineWidth = 2;
        ctx.strokeStyle = 'red';
        ctx.beginPath()
        // canvas y軸取反
        y1 = -y1
        y2 = -y2
        y3 = -y3
        ctx.moveTo(x1 * zoom + oX + dx, y1 * zoom + oY + dy)
        ctx.lineTo(x2 * zoom + oX + dx, y2 * zoom + oY + dy)
        ctx.lineTo(x3 * zoom + oX + dx, y3 * zoom + oY + dy)
        ctx.closePath()
        ctx.stroke();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黍檩,一起剝皮案震驚了整個濱河市叉袍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刽酱,老刑警劉巖喳逛,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肛跌,居然都是意外死亡艺配,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門衍慎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來转唉,“玉大人,你說我怎么就攤上這事稳捆≡ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵乔夯,是天一觀的道長砖织。 經(jīng)常有香客問我,道長末荐,這世上最難降的妖魔是什么侧纯? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮甲脏,結(jié)果婚禮上眶熬,老公的妹妹穿的比我還像新娘。我一直安慰自己块请,他們只是感情好娜氏,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墩新,像睡著了一般贸弥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上海渊,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天绵疲,我揣著相機與錄音哲鸳,去河邊找鬼。 笑死最岗,一個胖子當(dāng)著我的面吹牛帕胆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播般渡,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芙盘!你這毒婦竟也來了驯用?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤儒老,失蹤者是張志新(化名)和其女友劉穎蝴乔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驮樊,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡薇正,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了囚衔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挖腰。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖练湿,靈堂內(nèi)的尸體忽然破棺而出猴仑,到底是詐尸還是另有隱情,我是刑警寧澤肥哎,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布辽俗,位于F島的核電站,受9級特大地震影響篡诽,放射性物質(zhì)發(fā)生泄漏崖飘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一杈女、第九天 我趴在偏房一處隱蔽的房頂上張望朱浴。 院中可真熱鬧,春花似錦碧信、人聲如沸赊琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躏筏。三九已至,卻和暖如春呈枉,著一層夾襖步出監(jiān)牢的瞬間趁尼,已是汗流浹背埃碱。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酥泞,地道東北人砚殿。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像芝囤,于是被迫代替她去往敵國和親似炎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355