Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
方是個結構簡單而變化無窮的神奇玩具。那么如何在萬能的瀏覽器里模擬出魔方的無盡變換,又如何將其還原呢?下面讓我們一步步地來一探究竟吧。
拆解過魔方的同學可能知道,現實中魔方的內部結構包含了中軸、彈簧、螺絲等機械裝置。但當我們只是想要「模擬」它的時候,我們只需抓住它最顯著的性質即可——3x3x3 的一組立方體:
上圖演示了魔方最基本的思維模型。但光有這樣的感性認識還不夠:組成魔方的每個塊并非隨意安置,它們之間有著細微的區別:
將以上四種塊的數量相加,正好是 3^3=27 塊。對這些塊,你所能使用的唯一操作(或者說變換)方式,就是在不同面上的旋轉。那么,我們該如何標識出一次旋轉操作呢?
設想你的手里「端正地」拿著一個魔方,我們將此時面對你的那一面定義為 Front,背對的一面定義為 Back。類似地,我們有了 Left / Right / Upper / Down 來標識其余各面。當你旋轉某一面時,我們用這一面的簡寫(F / B / L / R / U / D)來標識在這一面上的一次順時針 90 度旋轉。對于一次逆時針的旋轉,我們則用 F' / U' 這樣帶 ' 的記號來表達。如果你旋轉了 180 度,那么可以用形如 R2 / U2 的方式表示。如下圖的 5 次操作,如果我們約定藍色一面為 Front,其旋轉序列就是 F' R' L' B' F':
關于魔方的基礎結構和變換方式,知道這些就足夠了。下面我們需要考慮這個問題:如何設計一個數據結構來保存的魔方狀態,并使用編程語言來實現某個旋轉變換呢?
喜歡基于「面向對象」抽象的同學可能很快就能想到,我們可以為每個塊設計一個 Block 基類,然后用形如 CornerBlock 和 EdgeBlock 的類來抽象棱塊和角塊,在每個角塊實例中還可以保存這個角塊到它相鄰三個棱塊的引用……這樣一個魔方的 Cube 對象只需持有對中心塊的引用,就可以基于各塊實例的鄰接屬性保存整個魔方了。
上面這種實現很類似于鏈表,它可以 O(1) 地實現「給定某個塊,查找其鄰接塊」的操作,但不難發現,它需要 O(N) 的復雜度來實現形如「某個位置的塊在哪里」這樣的查找操作,基于它的旋轉操作也并不十分符合直覺。相對地,另一種顯得「過于暴力」的方式反而相當實用:直接開辟一個長度為 27 的數組,在其中存儲每一塊的顏色信息即可。
為什么可以這樣呢?我們知道,數組在基于下標訪問時,具有 O(1) 的時間復雜度。而如果我們在一個三維坐標系中定位魔方的每一個塊,那么每個塊的空間坐標都可以唯一地映射到數組的下標上。更進一步地,我們可以令 x, y, z 分別取 -1, 0, 1 這三個值來表達一個塊在其方向上可能的位置,這時,例如前面所定義的一次 U 旋轉,剛好就是對所有 y 軸坐標值為 1 的塊的旋轉。這個良好的性質很有利于實現對魔方的變換操作。
在約定好數據結構之后,我們如何實現對魔方的一次旋轉變換呢?可能有些同學會直接將這個操作與三維空間中的四階變換矩陣聯系起來。但只要注意到一次旋轉的角度都是 90 度的整數倍,我們可以利用數學性質極大地簡化這一操作:
在旋轉 90 度時,旋轉面上每個角塊都旋轉到了該面上的「下一個」角塊的位置上,棱塊也是這樣。故而,我們只需要循環交替地在每個塊的「下一個」位置賦值,就能輕松地將塊「移動」到其新位置上。但這還不夠:每個新位置上的塊,還需要對其自身六個面的顏色做一次「自旋」,才能將它的朝向指向正確的位置。這也是一次交替的賦值操作。從而,一次三維空間繞某個面中心的旋轉操作,就被我們分解為了一次平移操作和一次繞各塊中心的旋轉操作。只需要 30 余行代碼,我們就能實現這一魔方最核心的變換機制:
rotate (center, clockwise=true) {
const axis=center.indexOf(1) + center.indexOf(-1) + 1
// Fix y direction in right-handed coordinate system.
clockwise=center[1] !==0 ? !clockwise : clockwise
// Fix directions whose faces are opposite to axis.
clockwise=center[axis]===1 ? clockwise : !clockwise
let cs=[[1, 1], [1, -1], [-1, -1], [-1, 1]] // corner coords
let es=[[0, 1], [1, 0], [0, -1], [-1, 0]] // edge coords
const prepareCoord=coord=> coord.splice(axis, 0, center[axis])
cs.forEach(prepareCoord); es.forEach(prepareCoord)
if (!clockwise) { cs=cs.reverse(); es=es.reverse() }
// 移動每個塊到其新位置
const rotateBlocks=([a, b, c, d])=> {
const set=(a, b)=> { for (let i=0; i < 6; i++) a[i]=b[i] }
const tmp=[]; set(tmp, a); set(a, d); set(d, c); set(c, b); set(b, tmp)
}
const colorsAt=coord=> this.getBlock(coord).colors
rotateBlocks(cs.map(colorsAt)); rotateBlocks(es.map(colorsAt))
// 調整每個塊的自旋朝向
const swap=[
[[F, U, B, D], [L, F, R, B], [L, U, R, D]],
[[F, D, B, U], [F, L, B, R], [D, R, U, L]]
][clockwise ? 0 : 1][axis]
const rotateFaces=coord=> {
const block=colorsAt(coord)
;[block[swap[1]], block[swap[2]], block[swap[3]], block[swap[0]]]=[block[swap[0]], block[swap[1]], block[swap[2]], block[swap[3]]]
}
cs.forEach(rotateFaces); es.forEach(rotateFaces)
return this
}
復制代碼
這個實現的效率應該不差:在筆者的瀏覽器里,上面的代碼可以支持每秒 30 萬次的旋轉變換。為什么在這里我們需要在意性能呢?在魔方的場景下,有一個非常不同的地方,即狀態的有效性與校驗。
熟悉魔方的同學應該知道,并不是隨便給每塊涂上不同顏色的魔方都是可以還原的。在普通的業務開發領域,數據的有效性和校驗常常可以通過類型系統來保證。但對于一個打亂的魔方,保證它的可解性則是一個困難的數學問題。故而我們在保存魔方狀態時,只有保存從六面同色的初始狀態到當前狀態下的所有變換步驟,才能保證這個狀態一定是可解的。這樣一來,反序列化一個魔方狀態的開銷就與操作步驟數量之間有了 O(N) 的關聯。好在一個實際把玩中的魔方狀態一般只會在 100 步之內,故而上面以犧牲時間復雜度換取數據有效性的代價應當是值得的。另外,這個方式可以非常簡單地實現魔方任意狀態之間的時間旅行:從初始狀態走到任意一步的歷史狀態,都只需要疊加上它們之間一系列的旋轉 diff 操作即可。這是一個很可靠的思維模型。
上面的實現中有一個特別之處:當坐標軸是 y 軸時,我們為旋轉方向進行了一次取反操作。這初看起來并不符合直覺,但其背后卻是坐標系定義的問題:如果你推導過每個塊在順時針變換時所處的下一個位置,那么在高中教科書和 WebGL 所用的右手坐標系中,繞 y 軸旋轉時各個塊的下一個位置,其交換順序與 x 軸和 z 軸是相反的。反而在 DirectX 的左手坐標系中,旋轉操作的正負能完全和坐標系的朝向一致。筆者作為區區碼農,并不了解這背后的對稱性是否蘊含了什么深刻的數學原理,希望數學大佬們解惑。
到此為止,我們已經基本完成了對魔方狀態的抽象和變換算法的設計了。但相信很多同學可能更好奇的是這個問題:在瀏覽器環境下,我們該如何渲染出魔方呢?讓我們來看看吧。
在瀏覽器這個以無數的二維矩形作為排版原語的世界里,要想渲染魔方這樣的三維物體并不是件查個文檔寫幾行膠水代碼就可以搞定的事情。好在我們有 WebGL 這樣的三維圖形庫可供差遣(當然了,相信熟悉樣式的同學應該是可以使用 CSS 來渲染魔方的,可惜筆者的 CSS 水平很菜)。
由于魔方思維模型的簡單性,要渲染它并不需要使用圖形學中紋理、光照和陰影等高級特性,只需要最基本的幾何圖形繪制特性就足夠了。正因為如此,筆者在這里只使用了完全原生的 WebGL API 來繪制魔方。籠統地說,渲染魔方這樣的一組立方體,所需要的步驟大致如下:
在前文中,我們設計的數據結構使用了長度為 27 的數組來存儲 [-1, -1, -1] 到 [1, 1, 1] 的一系列塊。在一個三重的 for 循環里,逐個將這些塊繪制到屏幕上的邏輯大概就像前面看到的這張圖:
需要注意的是,并不是越接近底層的代碼就一定越快。例如在最早的實現中,筆者直接通過循環調用來自(或者說抄自)MDN 的 3D 立方體例程來完成 27 個小塊的渲染。這時對于 27 個立方體區區不足千個頂點,60 幀繪制動畫時的 CPU 占用率都可能跑滿。經過定位,發現重復的 CPU 與 GPU 交互是一個大忌:從 CPU 向 GPU 傳遞數據,以及最終對 GPU 繪圖 API 的調用,都具有較大的固定開銷。一般我們需要將一幀中 Draw Call 的數量控制在 20 個以內,對于 27 個立方體就使用 27 次 Draw Call 的做法顯然是個反模式。在將代碼改造為一次批量傳入全部頂點并調用一次 drawElements 后,即可實現流暢的 60 幀動畫了 :)
在實現基本的渲染機制后,魔方整體的旋轉效果可以通過對模-視矩陣做矩陣乘法來實現。模-視矩陣會在頂點著色器由 GPU 中對每一個頂點并行地計算,得到頂點變換后的 gl_Position 位置。但對于單個面的旋轉,我們選擇了先在 CPU 中計算好頂點位置,再將其傳入頂點緩沖區。這和魔方旋轉動畫的實現原理直接相關:
我們首先需要設計用于渲染一幀的 render API。考慮到魔方在繪制時可能存在對某個面一定程度的旋轉,這個無狀態的渲染 API 接口形如:
render (rX=0, rY=0, moveFace=null, moveAngle=0) {
if (!this.gl) throw new Error('Missing WebGL context!')
this.buffer=getBuffer(this.gl, this.blocks, moveFace, moveAngle)
renderFrame(this.gl, this.programInfo, this.buffer, rX, rY)
}
復制代碼
而對單個面的旋轉過程中,我們可以使用瀏覽器的 requestAnimationFrame API 來實現基本的時序控制。一次調用 animate 的旋轉返回一個在單次旋轉結束時 resolve 的 Promise,其實現如下:
animate (move=null, duration=500) {
if (move && move.length===0) return Promise.resolve()
if (!move || this.__ANIMATING) throw new Error('Unable to animate!')
this.__ANIMATING=true
let k=move.includes("'") ? 1 : -1
if (/B|D|L/.test(move)) k=k * -1
const beginTime=+new Date()
return new Promise((resolve, reject)=> {
const tick=()=> {
const diff=+new Date() - beginTime
const percentage=diff / duration
const face=move.replace("'", '')
if (percentage < 1) {
this.render(this.rX, this.rY, face, 90 * percentage * k)
window.requestAnimationFrame(tick)
} else {
this.move(move)
this.render(this.rX, this.rY, null, 0)
this.__ANIMATING=false
resolve()
}
}
window.requestAnimationFrame(tick)
})
}
復制代碼
在實現了單次旋轉后,如何支持連續的多次旋轉呢?本著能偷懶就偷懶的想法,筆者對上面的函數進行了不改動已有邏輯的遞歸化改造,只需要在原函數入口處加入如下幾行,就可以使支持傳入數組為參數來遞歸調用自身,并在傳入的連續動畫數組長度為 1 時作為遞歸的出口,從而輕松地實現連續的動畫效果:
if (Array.isArray(move) && move.length > 1) {
const lastMove=move.pop()
// 返回遞歸得到的 Promise
return this.animate(move).then(()=> this.animate(lastMove))
} else if (move.length===1) move=move[0] // 繼續已有邏輯
復制代碼
到這里,一個可以供人體驗的魔方基本就可以在瀏覽器里跑起來了。但這還不是我們最終的目標:我們該怎么自動還原一個魔方呢?
魔方的還原算法在學術界已有很深入的研究,計算機在 20 步之內可以解出任意狀態的魔方,也有成熟的輪子可以直接調用。但作為一個(高中時)曾經的魔方業余愛好者,筆者這里更關注的是「如何模擬出我自己還原魔方的操作」,故而在這里我們要介紹的是簡單易懂的 CFOP 層先算法。
在開始前,有必要強調一個前文中一筆帶過的概念:在旋轉時,魔方中心塊之間的相對位置始終不會發生變化。如下圖:
因此,在魔方旋轉時,我們只需關注角塊和棱塊是否歸位即可。在 CFOP 層先法中,歸位全部角塊和棱塊的步驟,被分為了逐次遞進的四步:
讓我們依次來看看每一步都發生了什么吧。
這一步可以說是最簡單也最難的,在此我們的目標是還原四個底部棱塊,像這樣:
對一個完全打亂的魔方,每個目標棱塊都可能以兩種不同的朝向出現在任意一個棱塊的位置上。為什么有兩種朝向呢?請看下圖:
這是最簡單的一種情形,此時直接做一次 R2 旋轉即可使紅白棱塊歸位。但下面這種情況也是完全合法的:
這時由于棱塊的朝向不同,所需的步驟就完全不同了。但總的來說,構成十字所需的棱塊可能出現的位置總是有限的。拆解分類出所有可能的情形后,我們不難使用貪心策略來匹配:
這個最簡單的策略很接近語法分析中向前看符號數量為 1 時的算法,不過這里不需要回溯。實現機制可以抽象如下:
solveCross () {
const clonedCube=new Cube(null, this.cube.moves)
const moveSteps=[]
while (true) {
const lostEdgeCoords=findCrossCoords(clonedCube)
if (!lostEdgeCoords.length) break
moveSteps.push(solveCrossEdge(clonedCube, lostEdgeCoords[0]))
}
return moveSteps
}
復制代碼
這個實現原理并不復雜,其代價就是過小的局部最優造成了較多的冗余步驟。如果同時觀察 2 個甚至更多的棱塊狀態并將其一并歸位,其效率顯然能得到提升(這時的實現難度也是水漲船高)。作為對比,一流的魔方玩家可以在 7 步內完成十字,但這個算法實現卻需要 20 步左右——不過這里意思已經到了,各位看官就先不要太苛刻啦。
這里的目標是在底部十字完成的基礎上,完成底部兩層所有塊的歸位。我們的目標是實現這樣的狀態:
這個步驟中,我們以 Slot 和 Pair 的概念作為還原的基本元素。相鄰的十字之間所間隔的一個棱和一個角,構成了一個 Slot,而它們所對應的兩個目標塊則稱為一個 Pair。故而這個步驟中,我們只需要重復四次將 Pair 放入 Slot 中的操作即可。一次最簡單的操作大概是這樣的:
上圖將頂層的一對 Pair 放入了藍紅相間的 Slot 中。類似于之前解十字時的情形,這一步中的每個棱塊和角塊也有不同的位置和朝向。如果它們都在頂層,那么我們可以通過已有的匹配規則來實現匹配;如果它們在其它的 Slot 中,那么我們就遞歸地執行「將 Pair 從其它 Slot 中旋出」的算法,直到這組 Pair 都位于頂層為止。
這一步的還原算法與下面的步驟相當接近,稍后一并介紹。
完成了前兩層的還原后,我們最后所需要處理的就是頂層的 8 個棱塊與角塊了。首先是頂面同色的步驟,將各塊調整到正確的朝向,實現頂面同色(一般采用白色作為底面,此時按照約定,黃色為頂面):
而后是頂層順序的調整。這一步在不改變棱與角朝向的前提下,改變它們的排列順序,最終完成整個魔方的還原:
從前兩層的還原到頂層的還原步驟中,都有大量的魔方公式規則可供匹配使用。如何將這些現成的規則應用到還原算法中呢?我們可以使用規則驅動的方式來使用它們。
了解編譯過程的同學應該知道,語法分析的過程可以通過編寫一系列的語法規則來實現。而在魔方還原時,我們也有大量的規則可供使用。一條規則的匹配部分大概是這樣的:
在頂面同色過程中,滿足上述 "pattern" 的頂面,可以通過 U L U' R' U L' U' R 的步驟來還原。類似地,在還原頂層順序時,規則的匹配方式形如這樣:
滿足這條規則的頂層狀態可以通過該規則所定義的步驟求解:R2 U' R' U' R U R U R U' R。這樣一來,只需要實現對規則的匹配和執行操作,規則的邏輯就可以完全與代碼邏輯解耦,變為可配置的 JSON 格式數據。用于還原前兩層的一條規則格式形如:
{
match: { [E]: topEdge(COLOR_F, E), [SE]: SE_D_AS_F },
moves: "U (R U' R')"
}
復制代碼
頂層同色的規則格式形如:
{
match: { [NW]: L, [NE]: R, [SE]: R, [SW]: L },
moves: "R U R' U R U' R' U R U U R'"
}
復制代碼
頂面順序的規則格式形如:
{
match: { [N]: W, [W]: [E], [E]: N },
moves: "R R U' R' U' R U R U R U' R"
}
復制代碼
這里的 NW / E / SE 是筆者的實現中基于九宮格東西南北方向定位的簡寫。在實現了對規則的自動匹配和應用之后,CFOP 中后面三步的實現方式可以說大同小異,主要的工作集中在一些與旋轉相關的 mapping 處理。
在整個還原過程中,一共有上百條規則需要匹配。對于這么多的規則,該如何保證它們的正確性呢?在 TDD 測試驅動開發的理念中,開發者需要通過編寫各種繁冗的測試用例來實現對代碼邏輯的覆蓋。但在魔方領域,筆者發現了一種優雅得多的性質:任何一條規則本身,就是自己的測試用例!如這條規則:
{
match: { [N]: W, [W]: [E], [E]: N },
moves: "R R U' R' U' R U R U R U' R"
}
復制代碼
我們只需要將 moves 中的每一步順序顛倒地輸入初始狀態的魔方,就可以用這個狀態來驗證規則是否能夠匹配,以及魔方是否能基于該規則還原了。這個性質使得我很容易地編寫了下面這樣簡單的代碼,自動驗證每條輸入規則的正確性:
const flip=moves=> moves.map(x=> x.length > 1 ? x[0] : x + "'").reverse()
OLL.forEach(rule=> {
const rMoves=flip(rule.moves)
const cube=new Cube(null, rMoves)
if (
matchOrientationRule(cube, rule) &&
isOrientationSolved(cube.move(rule.moves))
) {
console.log('OLL test pass', rule.id)
} else console.error('Error OLL rule match', rule.id)
})
復制代碼
在這個支持自測試的規則匹配算法基礎上,求解魔方的全部步驟就這樣計算出來了 :)
經過半個多月業余時間的折騰,筆者實現了一個非常小巧的魔方求解模擬器 Freecube。它支持三階魔方狀態的渲染和逐步求解,還提供了旋轉與求解的 API 可供復用。由于它沒有使用任何第三方依賴并使用了各種力求精簡的「技巧」,因而它的體積被控制在了壓縮后 10KB 內。歡迎移步 GitHub 觀光 XD
Freecube 案例地址:https://ewind.us/h5/freecube/
Freecube 是筆者在很多地方忙里偷閑地實現的:咖啡廳、動車、公交車甚至飯桌上……即便寫不了代碼的場合,也可以拿平板寫寫畫畫來設計它。它的靈感來自于 @youngdro 神奇的吉他和弦算法博文,
https://juejin.im/post/5b2627d051882574ac7848a4
另外感謝大佬的指點和某人對 README 文檔的審校 XD
Github地址:https://github.com/doodlewind/freecube
原地址:https://juejin.im/post/5b837c0b51882542d950efb4
久沒參與魔方的發布工作了,今天提筆,有種莫名的生疏和惶恐,從下午四點半一直坐到現在,3個小時,刪刪寫寫。千言無語,千頭萬緒,千百般滋味涌上心頭,真的很懷念那些年每個周五定期一更的日子,簡單而快樂。
2006年12月Vista優化大師發布第一個測試版,再到2009年9月發布魔方0.1,時光荏苒,便過去了9年。很多當初最早的那批朋友,現在都成了老友,有時候一覺醒來,發現軟媒的那個最老用戶群里的消息閃爍,由衷的開心,沒有什么比熟悉的感覺更有韻味。
產品部的魔方一哥過來催文了,盡管他說理解我的心情啊什么的,但是為了保持一貫的不加班作風,我得直入主題了——
魔方6.16正式版現在發布,“忍不住”還是讓產品組加了新功能,本來說好的要克制加新功能的沖動,重點大幅改進清理等原有常用功能的。
這次忍不住要加的新功能,大家在標題里面已經看到了,就是一鍵提取微軟官方的精美聚焦壁紙(美化大師頂部加入了“聚焦壁紙”)。熟悉微軟的朋友都知道,Win10TH2開始系統增加了“Windows 聚焦”壁紙,大家在系統設置的“個性化”-“鎖屏設置”里面可以設置鎖屏的背景壁紙為“Windows 聚焦”,如下圖所示:
這些微軟官方提供的鎖屏壁紙還是非常精美的,會自動的下載并切換,于是魔方便加入了提取功能,需要注意的是,這兒的提取,是提取的本機已經下載的,如果您之前沒有開啟過Windows聚焦功能,是抓不到的。這個抓取功能更方便的是讓大家隨時保存最新的。那過去的好看聚焦壁紙怎么辦?別著急,我們在軟件界面提供了所有Win10歷史聚焦壁紙下載大全的鏈接,很貼心的說。
當然,這次魔方還有其他的有愛更新,例如清理大師的重復文件查找支持了批量選擇和刪除操作,例如設置大師中加入了讓資源管理器關閉mkv文件的預覽以防止卡頓,軟媒雷達、軟媒時間、WiFi助手、軟媒壓縮等都有界面和功能修復改進。
具體更新內容的細節,請看下面的更新歷史吧!
PS:按照慣例,軟媒魔方將在發布數十分鐘后才放開自動升級。
一、軟媒魔方更新歷史
軟媒魔方 6.1.6.0 正式版 - 2015年12月17日
魔方主程序 6.1.6.0:
新增:應用大全 - 增加旗魚瀏覽器PC版入口
軟媒美化大師 3.6.9.0:
新增:針對Win10 TH2增加Windows聚焦壁紙一鍵提取功能
軟媒時間 3.1.3.0:
修正:界面 - 多云和陰天的小圖標弄反的問題修正:界面 - 系統開啟高DPI的時候,窗口太小的問題
軟媒清理大師 3.7.3.0:
新增:隱私清理 - Office 2016打開歷史記錄清理
改進:重復文件查找 - 支持批量操作改進:注冊表清理 - 屏蔽注冊表清理功能
修正:隱私清理 - Office 2013打開歷史記錄清理不掉的問題
軟媒設置大師 3.6.8.0:
新增:資源管理器 - 關閉MKV視頻預覽
軟媒雷達 6.0.7.0:
修正:本機信息 - 讀取IE的Flash Player版本號錯誤的問題修正:界面 - 系統開啟高DPI的時候,窗口太小的問題
軟媒IE管理大師 1.9.8.0:
修正:界面 - 系統開啟高DPI的時候,窗口太小的問題
軟媒WiFi助手 1.1.8.0:
修正:穩定性 - 啟動WiFi助手時可能發生的崩潰問題
軟媒壓縮 1.1.5.0:
修正:界面 - 系統開啟高DPI的時候,窗口太小的問題
二、為什么大家都在用魔方?
軟媒魔方好不好?軟媒魔方有什么用?為什么要用軟媒魔方?
先列出一些基本組件功能:
1、清理大師:一鍵清理、深度清理、注冊表清理、字體清理,還有隱私清理。。。難道你不需要?
2、美化大師:改系統字體、DIY win7開始按鈕、設置開機動畫、破解系統主題、修改系統聲音。。。怎么個性怎么玩,美化大師全搞定!
3、優化大師:一鍵加速、添加、刪除系統啟動項,讓你輕松掌控系統進程的開啟!
4、軟媒時間,軟媒全球首創獨創的創意,任務欄時間區加入農歷、天氣等顯示,不占任何額外空間,超NB!
5、軟媒桌面:哈,Windows系統里多了類似蘋果Mac OS X的快捷欄,方便大發了。
6、軟件管家:精選裝機必備軟件大全,下載杠杠的……
7、系統雷達:任務欄窗口+桌面懸浮窗自由隨意選擇,實時監控網絡流量、CPU、內存占用、磁盤讀寫,簡單、清晰、方便!
8、U盤啟動:一鍵制作U盤系統安裝盤,裝機還是PE維護簡直輕松到極點!
9、硬盤裝機:僅需兩步,輕松幫你重裝系統,win7、win8、win10,想裝什么裝什么,你肯定需要!
10、WiFi共享助手:超級簡單,打開軟件,一鍵開啟熱點,立馬擺脫手機流量不夠用的困擾!!親,你的流量還夠用嗎?
還有啥?上面列出的連一半功能都不到,還有網速測試、磁盤大師、文件校驗、文件解鎖、文件分割合并、文件粉碎……等等,還有好多功能,你能想到的基本都有!
軟媒魔方現在已經有4000萬用戶下載使用,好用沒得說!
三、軟媒魔方軟件截圖
只需一鍵,智能模式讓你可以放心的把軟媒魔方介紹給你的老婆、小姨子和表妹……
右上角輕松切換到專業模式,熟悉中包含著科學改進后的經典布局
軟媒時間,風云變幻-不占用任何額外空間,萬年歷天氣鬧鐘記事本在任務欄時間區完美呈現;
軟媒桌面,好玩好看-喜歡的鼠標拖進來,不愛的鼠標拖出去,桌面干凈整潔靈動驚艷;
軟媒雷達,實時偵探-把握您愛機的每一跳脈動,精確掌控系統軟硬件的占用資源;
軟件管家,純凈精干-編輯精選裝機必備的500款最常用軟件,一鍵安裝絕無插件;
四、軟媒魔方下載信息
初級用戶解惑:安裝包和綠色版有什么不同?安裝版下載后直接雙擊運行即可進入向導安裝,方便快捷。綠色版是ZIP壓縮格式,直接解壓到你指定的文件夾路徑下。
軟媒 - 存在,創造價值。
微信搜索“IT之家”關注搶6s大禮!下載IT之家客戶端(戳這里)也可參與評論抽樓層大獎!
oogle 的第一個 Doodle 誕生于 1998 年 8 月 30 日。當時,公司的兩位聯合創始人去內華達參加“火人節”。他們在主頁的 Google 后面放了一個燃火的小人,以表示自己外出旅行了。這個 Doodle 非常簡單,但是,把公司 Logo 與重要紀念日結合的想法就此誕生。多年以來,Doodle 已經成為 Google 文化的一部分,傳達著科技背后的人文化精神。
如今,Google 內部有專業的 Doodle 團隊,擁有 10 名插畫師,4 個全職開發者和 2 個項目經理。他們會收集創意,對其進行定期整理,并且制定 Doodle 呈現計劃。Doodle 的形式也已經豐富多彩了。除了靜態圖片之外,它也可以是動態圖片、動畫短片,甚至是交互性的小游戲。2010 年的吃豆人就是讓人印象深刻的一個互動 Doodle。今年的 5 月 19 日,為了紀念魔方發明 40 周年,Google 特意制作了一個交互性的小游戲:魔方 Doodle。
魔方 Doodle 看起來并不復雜,但是對于 Doodle 團隊來說,它是極具挑戰性的一次嘗試。如果你玩過網上的魔方游戲,或許會注意到,它們基本都是使用了 Flash 技術,而且操作上很是糟糕。Google 的魔方 Doodle 使用的完全是網頁技術。
“魔方 Doodle 是人們多次建議過的東西,但是我們一直覺得,制作它的網頁技術還沒有成熟,” Doodle 的團隊主管 Ryan Gemick 對 Wired 網站說。 Google 創意實驗室把它稱作是,“我們最具技術野心的 Doodle 之一。”
魔方 Doodle 能夠實現,是因為近來大多數瀏覽器都開始支持 CSS 3-D Transforms。“CSS 3-D Transforms 可以讓我們把魔方展現在 3D 空間,而不是一種柵格化的 2D 體驗,” 主工程師 Kristopher Hom 說,“這使它鮮活起來,當你移動鼠標的時候,你能看到魔方在 3D 空間里轉動。”
Ryan Germick 說,他們面臨的最大挑戰是,如何讓游戲體現出魔方設計上的簡樸功能。“從設計角度來說,我們使它盡可能的簡單、樸素,” Germick 解釋說,“ ‘Google’ 的拼寫是極簡、抽象和幾何形式的。界面極簡化,只告訴你移動了多少步。”
對魔方Doodle 背后的技術感興趣?Google 已經把源代碼全部開源了。任何人都可以去改進它,去制作更好的魔方游戲。同時,Google 還與自由科學中心合作,在其舉辦的魔方 40 周年紀念展上放置了一個互動的魔方。(魔方誕生 40 周年之際,魔方創始人、69 歲的匈牙利發明家 Enno Rubik 與美國新澤西州的自由科學中心合作舉辦了魔方展。在展示的魔方中,有第一個原型,制造材料是木頭和橡皮筋,還有世界上最貴的魔方,18 K 金打造,1360 塊寶石,價值估計為 150 萬英鎊。)
在 Ryan Germick 看來,Google 制作 Doodle 的目的,是為了贊賞魔方中體現的創造力。“如果你小時候得到了一個魔方,你對它感興趣的原因是因為你是一個問題解決者,或者你對那些促使你以后走向編程、工程和技術的東西感興趣。” 他說,“我認為,我們對它感興趣的原因是,它是一個符號,一個解決問題的符號,一個簡單與復雜并存的符號。這是我們真正想要慶祝的東西。”
圖片來自 florianmecl
*請認真填寫需求信息,我們會在24小時內與您取得聯系。