Skip to content

Commit

Permalink
Factored out the "side drift" code into a Pov class that at least *I*…
Browse files Browse the repository at this point in the history
… now actually understand.
  • Loading branch information
larspetrus committed Mar 25, 2017
1 parent 58456ec commit 582a7ea
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 95 deletions.
3 changes: 3 additions & 0 deletions misc/rptest_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<body>
<div id="mocha"></div>

<!-- All JS source files have to be listed manually here, in dependency order. I'd love to learn a better way! -->

<script src="lib/jquery-3.1.1.min.js"></script>
<script src="https://cdn.rawgit.com/chaijs/chai/2.3.0/chai.js"></script>
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
Expand All @@ -27,6 +29,7 @@
<script src="local/test_js/src/EventHandlers.js"></script>
<script src="local/test_js/src/Move.js"></script>
<script src="local/test_js/src/Pieces3D.js"></script>
<script src="local/test_js/src/Pov.js"></script>
<script src="local/test_js/src/Tweaks.js"></script>
<script src="local/test_js/src/document.js"></script>
<script src="local/test_js/src/changers/TimedChanger.js"></script>
Expand Down
30 changes: 5 additions & 25 deletions src/Alg.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -97,35 +97,15 @@ class Alg
new Move(code, @world3d, @speed)

unhand: ->
drift = {U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B'} # drift.U says what center is on U
colors = new Colors(drift, "", "")

pov = new Pov()
result = []
for move in @moves
drifted_move = this.drift(move.as_brdflu(), drift)
result.push(drifted_move)
move.track_drift(drift)
result.push(pov.hand_to_cube(move.as_brdflu()))
pov.track(move)
result.join(' ').replace(/[ ]+/g, ' ').replace(/^ +| +$/g, '')

drift: (code, side_drift) ->
return code unless code

inverted_drift = {}
for own key, value of side_drift
inverted_drift[value] = key
inverted_drift[value.toLowerCase()] = key.toLowerCase()

((inverted_drift[char] || char) for char in code.split('')).join('')


@side_drift: (moves) ->
new Alg(moves, null, "")._side_drift()

_side_drift: ->
drift = {U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B'}
for move in @moves
move.track_drift(drift)
drift
@pov_from: (move_codes) ->
new Pov(new Alg(move_codes).moves)

_update_dom: (time = 'later') ->
if @dom && @moves.length > 0
Expand Down
34 changes: 10 additions & 24 deletions src/Colors.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

class Colors

constructor: (side_drift, colored, solved, tweaks, colors = "") ->
@colored = new Cubexp(this._undrift(colored, side_drift) || "*")
@solved = new Cubexp(this._undrift(solved, side_drift))
@tweaks = new Tweaks(this._undrift(tweaks, side_drift))
@side_colors = Colors._set_colors(colors, side_drift)
constructor: (pov, colored, solved, tweaks, overrides = "") ->
@colored = new Cubexp(pov.cube_to_hand(colored) || "*")
@solved = new Cubexp(pov.cube_to_hand(solved))
@tweaks = new Tweaks(pov.cube_to_hand(tweaks))
@side_colors = Colors._set_colors(overrides, pov.hand_to_cube_map())

to_draw: (piece_name, side) ->
result = { hovers: false, color: this.of(side) }
Expand Down Expand Up @@ -38,30 +38,16 @@ class Colors
throw new Error("Unknown sticker type '#{sticker_type}'")
@side_colors[type]

_undrift: (code, side_drift) ->
return code unless code

uncased_drift = {}
for own key, value of side_drift
uncased_drift[key] = value
uncased_drift[key.toLowerCase()] = value.toLowerCase()

(uncased_drift[char] || char for char in code.split('')).join('')

DEFAULT_COLORS = {g:'#0d0', b:'#07f', r:'red', o:'orange', y:'yellow', w:'#eee'}
@_set_colors: (overrides, side_drift) ->
dc = DEFAULT_COLORS
@_set_colors: (config_colors, h2c_map) ->
dc = DEFAULT_COLORS # shorten name for readability
result = {R:dc.g, L:dc.b, F:dc.r, B:dc.o, U:dc.y, D:dc.w, solved:'#444', ignored:'#888', cube:'black'}

for override in overrides.split(' ')
for override in config_colors.split(' ')
[type, color] = override.split(':')
type = {s:'solved', i:'ignored', c:'cube'}[type] || type
result[type] = DEFAULT_COLORS[color] || color

inverted_drift = {}
for own key, value of side_drift
inverted_drift[value] = key

[r, d] = [result, inverted_drift]
[r.U, r.D, r.R, r.L, r.F, r.B] = [r[d.U], r[d.D], r[d.R], r[d.L], r[d.F], r[d.B]]
r = result # shorten name for readability
[r.U, r.D, r.R, r.L, r.F, r.B] = [r[h2c_map.U], r[h2c_map.D], r[h2c_map.R], r[h2c_map.L], r[h2c_map.F], r[h2c_map.B]]
result
4 changes: 2 additions & 2 deletions src/CompositeMove.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class CompositeMove
show_do: -> new ConcurrentChangers( (@moves.map (move) -> move.show_do()) )
show_undo:-> new ConcurrentChangers( (@moves.map (move) -> move.show_undo()) )

track_drift: (side_drift) ->
move.track_drift(side_drift) for move in @moves
track_pov: (pov_map) ->
move.track_pov(pov_map) for move in @moves

count: (count_rotations) ->
return 1 if @official_text
Expand Down
2 changes: 1 addition & 1 deletion src/Config.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Config

@alg = this.raw(ALG)
@algdisplay= this._alg_display()
@colors = new Colors(Alg.side_drift(@alg), this.raw(COLORED), this.raw(SOLVED), this.raw(TWEAKS), this.raw(COLORS))
@colors = new Colors(Alg.pov_from(@alg), this.raw(COLORED), this.raw(SOLVED), this.raw(TWEAKS), this.raw(COLORS))
@flags = this.raw(FLAGS)
@hover = this._hover()
@pov = this.raw(POV, "Ufr")
Expand Down
6 changes: 3 additions & 3 deletions src/Move.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class Move
unless @is_rotation
this.undo()

track_drift: (side_drift) ->
track_pov: (pov_map) ->
for cycle in [@layer.cycle1, @layer.cycle2] when cycle[0].length == 1 # center cycle
for side, location of side_drift
for side, location of pov_map
for i in [0..3]
if location == cycle[i]
side_drift[side] = cycle[(i-@turns+4)% 4]
pov_map[side] = cycle[(i-@turns+4)% 4]

as_brdflu: ->
return '' if @is_rotation
Expand Down
36 changes: 36 additions & 0 deletions src/Pov.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# POV = Point Of View. Cube notations has two POVs.
#
# Seen from the cube, U is always up, and there are only six kinds of moves: B, R, D, F, L, and U.
# Seen from the hands of a human, more moves exist (x, y, x, M, E, S, etc), and after a z2 move,
# U seen from the cube is D seen from the hands.
#
# This class keeps track of and maps between these POVs

class Pov
constructor: (moves) ->
@map = Pov.start_map()
this.track(moves) if moves

@start_map: ->
{B: 'B', D: 'D', F: 'F',L: 'L', R: 'R', U: 'U'}

track: (moves) ->
moves = [moves] unless Array.isArray(moves)
for move in moves
move.track_pov(@map)

hand_to_cube_map: ->
reverse_map = {}
for own key, value of @map
reverse_map[value] = key
reverse_map

cube_to_hand: (code) ->
this._case_map(@map, code)

hand_to_cube: (code) ->
this._case_map(this.hand_to_cube_map(), code)

_case_map: (map, code) ->
return code unless code
(map[char] || map[char.toUpperCase()]?.toLowerCase() || char for char in code.split('')).join('')
15 changes: 5 additions & 10 deletions test/Alg_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,11 @@ describe "Alg", ->
alg = new Alg("F R> U2+D' F<< LZ D+D>", world, new Config("algdisplay=rotations").algdisplay)
expect(alg.display_text().future).to.equal("F R> U2+D' F<< L2 D+D>")

it "#_side_drift", ->
world = null
expect(new Alg("F", world, "")._side_drift()).to.deep.equal(U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B')
expect(new Alg("M", world, "")._side_drift()).to.deep.equal(B: 'U', F: 'D', L: 'L', R: 'R', U: 'F', D: 'B')
expect(new Alg("M z", world, "")._side_drift()).to.deep.equal(L: 'U', R: 'D', F: 'L', B: 'R', U: 'F', D: 'B')
expect(new Alg("MZ", world, "")._side_drift()).to.deep.equal(U: 'D', D: 'U', L: 'L', R: 'R', F: 'B', B: 'F')

it "@side_drift", ->
expect(Alg.side_drift("F")).to.deep.equal(U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B')
expect(Alg.side_drift("M")).to.deep.equal(B: 'U', F: 'D', L: 'L', R: 'R', U: 'F', D: 'B')
it "pov_from", ->
expect(Alg.pov_from("F").map).to.deep.equal(U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B')
expect(Alg.pov_from("M").map).to.deep.equal(B: 'U', F: 'D', L: 'L', R: 'R', U: 'F', D: 'B')
expect(Alg.pov_from("M z").map).to.deep.equal(L: 'U', R: 'D', F: 'L', B: 'R', U: 'F', D: 'B')
expect(Alg.pov_from("MZ").map).to.deep.equal(U: 'D', D: 'U', L: 'L', R: 'R', F: 'B', B: 'F')

it "unhand", ->
expect(new Alg("F L2", null, "").unhand()).to.equal("F L2")
Expand Down
47 changes: 17 additions & 30 deletions test/Colors_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
#= require Colors
#= require Layer

nodrift = {U: 'U', D: 'D', L: 'L', R: 'R', F: 'F', B: 'B'}

describe "Colors", ->
describe "of", ->
it "has default values", ->
colors = new Colors(nodrift, "", "", "")
colors = new Colors(new Pov(), "", "", "")
expect(colors.of(Layer.R)).to.equal('#0d0')
expect(colors.of(Layer.L)).to.equal('#07f')
expect(colors.of(Layer.F)).to.equal('red')
Expand All @@ -24,7 +23,7 @@ describe "Colors", ->
colors.of('UNKNOWN')).to.throw(Error)

it "can change colors", ->
colors = new Colors(nodrift, "", "", "", "R:o L:#abc solved:r c:#123")
colors = new Colors(new Pov(), "", "", "", "R:o L:#abc solved:r c:#123")

expect(colors.of(Layer.R)).to.equal('orange')
expect(colors.of(Layer.L)).to.equal('#abc')
Expand All @@ -36,79 +35,67 @@ describe "Colors", ->

describe "#to_draw", ->
it "is colored by default", ->
colors = new Colors(nodrift, "", "")
colors = new Colors(new Pov(), "", "")
expect(colors.to_draw('UFR', 'F')).to.deep.equal(color: colors.of('F'), hovers: true)
expect(colors.to_draw('DB', 'B')).to.deep.equal(color: colors.of('B'), hovers: true)
expect(colors.to_draw('L', 'L')).to.deep.equal(color: colors.of('L'), hovers: true)

it "colors only specified stickers", ->
colors = new Colors(nodrift, "U*", "")
colors = new Colors(new Pov(), "U*", "")
expect(colors.to_draw('UFR', 'F')).to.deep.equal(color: colors.of('F'), hovers: true)
expect(colors.to_draw('DB', 'B')).to.deep.equal(color: colors.of('ignored'), hovers: false)
expect(colors.to_draw('L', 'L')).to.deep.equal(color: colors.of('ignored'), hovers: false)

it "solved overrides colored", ->
colors = new Colors(nodrift, "U*", "F*")
colors = new Colors(new Pov(), "U*", "F*")
expect(colors.to_draw('UFR', 'F')).to.deep.equal(color: colors.of('solved'), hovers: false)
expect(colors.to_draw('UR', 'U')).to.deep.equal(color: colors.of('U'), hovers: true)
expect(colors.to_draw('F', 'F')).to.deep.equal(color: colors.of('solved'), hovers: false)
expect(colors.to_draw('L', 'L')).to.deep.equal(color: colors.of('ignored'), hovers: false)

it "last tweak color wins", ->
colors = new Colors(nodrift, "*", "", "R:U* L:F*")
colors = new Colors(new Pov(), "*", "", "R:U* L:F*")
expect(colors.to_draw('D', 'D')).to.deep.equal(color: colors.of('D'), hovers: true) #untweaked
expect(colors.to_draw('U', 'U')).to.deep.equal(color: colors.of('R'), hovers: true) #tweaked
expect(colors.to_draw('F', 'F')).to.deep.equal(color: colors.of('L'), hovers: true) #tweaked
expect(colors.to_draw('UF', 'U')).to.deep.equal(color: colors.of('L'), hovers: true) #double tweaked

describe "tweaks", ->
it "sets X and colors", ->
colors = new Colors(nodrift, "", "*", ".Xx:uFR D.L:UfR")
colors = new Colors(new Pov(), "", "*", ".Xx:uFR D.L:UfR")

expect(colors.to_draw('UFR', 'U')).to.deep.equal(color: colors.of('D'), hovers: true)
expect(colors.to_draw('UFR', 'F')).to.deep.equal(color: colors.of('solved'), hovers: true, x_color: 'black')
expect(colors.to_draw('UFR', 'R')).to.deep.equal(color: colors.of('L'), hovers: true, x_color: 'white')

it "overrides colored and solved", ->
colors = new Colors(nodrift, "U*", "D*", "L:U R:D")
colors = new Colors(new Pov(), "U*", "D*", "L:U R:D")

expect(colors.to_draw('U', Layer.U).color).to.equal(colors.of(Layer.L))
expect(colors.to_draw('D', Layer.D).color).to.equal(colors.of(Layer.R))

describe "side drift adjustments", ->
z_drift = {L: 'U', R: 'D', U: 'R', D: 'L', F: 'F', B: 'B'}

describe "side pov adjustments", ->
it "side colors", ->
plain_colors = new Colors(nodrift, "", "", "")
drift_colors = new Colors(z_drift, "", "", "")
expect(drift_colors.of('F')).to.equal(plain_colors.of('F'))
expect(drift_colors.of('R')).to.equal(plain_colors.of('U'))
plain_colors = new Colors(new Pov(), "", "", "")
pov_colors = new Colors(new Pov(new Move("S")), "", "", "")
expect(pov_colors.of('F')).to.equal(plain_colors.of('F'))
expect(pov_colors.of('R')).to.equal(plain_colors.of('U'))

it "colored", ->
colors = new Colors(z_drift, "u", "", "")
colors = new Colors(new Pov(new Move("S")), "u", "", "")
expect(colors.to_draw('U', 'U')).to.deep.equal(color: colors.of('ignored'), hovers: false)
expect(colors.to_draw('R', 'R')).to.deep.equal(color: colors.of('R'), hovers: true)

it "solved", ->
colors = new Colors(z_drift, "Ufr", "r", "")
colors = new Colors(new Pov(new Move("S")), "Ufr", "r", "")
expect(colors.to_draw('R', 'R')).to.deep.equal(color: colors.of('ignored'), hovers: false)
expect(colors.to_draw('D', 'D')).to.deep.equal(color: colors.of('solved'), hovers: false)

it "tweaks", ->
untweaked = new Colors(z_drift, "", "", "")
untweaked = new Colors(new Pov(new Move("S")), "", "", "")
expect(untweaked.to_draw('RF', 'R'), 1).to.deep.equal(color: untweaked.of('R'), hovers: true)
expect(untweaked.to_draw('LU', 'L'), 22).to.deep.equal(color: untweaked.of('L'), hovers: true)

tweaked = new Colors(z_drift, "", "", "X:Uf RF:DL")
tweaked = new Colors(new Pov(new Move("S")), "", "", "X:Uf RF:DL")
expect(tweaked.to_draw('RF', 'R')).to.deep.equal(color: tweaked.of('R'), hovers: true, x_color: 'black')
expect(tweaked.to_draw('LU', 'L')).to.deep.equal(color: tweaked.of('D'), hovers: true)

describe "#_undrift", ->
drift = {U: 'D', D: 'U', R: 'L', L: 'R', F: 'F', B: 'B'}
colors = new Colors(nodrift, "", "")

it "handles upper case", ->
expect(colors._undrift("XYZ:URF", drift)).to.equal("XYZ:DLF")

it "handles lower case", ->
expect(colors._undrift("XYZ:Urf", drift)).to.equal("XYZ:Dlf")
9 changes: 9 additions & 0 deletions test/CompositeMove_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ describe "CompositeMove", ->
expect(new CompositeMove("B2+S2").as_brdflu()).to.equal("F2") # Bw2
expect(new CompositeMove("R2+M2+L2").as_brdflu()).to.equal("") # x
expect(new CompositeMove("U>+L").as_brdflu()).to.equal("L")

it "#track_pov", ->
map = Pov.start_map()

new CompositeMove("U2+D").track_pov(map)
expect(map).to.deep.equal(Pov.start_map())

new CompositeMove("B'+S").track_pov(map)
expect(map).to.deep.equal(B: "B", D: "L", F: "F", L: "U", R: "D", U: "R")
9 changes: 9 additions & 0 deletions test/Move_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ describe "Move", ->
expect(new Move("U>>").count(false)).to.equal(0)
expect(new Move("U>>").count(true)).to.equal(1)

it "#track_pov", ->
map = Pov.start_map()

new Move("U").track_pov(map)
expect(map).to.deep.equal(Pov.start_map())

new Move("S").track_pov(map)
expect(map).to.deep.equal(B: "B", D: "L", F: "F", L: "U", R: "D", U: "R")

it "#as_brdflu", ->
expect(new Move("U2").as_brdflu()).to.equal("U2")
expect(new Move("M").as_brdflu()).to.equal("L' R")
Expand Down
33 changes: 33 additions & 0 deletions test/Pov_spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#= require Pov

describe "Pov", ->
describe "track", ->
it "handles move or array", ->
pov = new Pov()
expect(pov.map).to.deep.equal(Pov.start_map())

pov.track(new Move("M"))
expect(pov.map).to.deep.equal(B: 'U', D: 'B', F: 'D', L: 'L', R: 'R', U: 'F')

pov = new Pov()
pov.track([new Move("M"), new Move("F'"), new Move("E2")])
expect(pov.map).to.deep.equal(B: 'U', D: 'F', F: 'D', L: 'R', R: 'L', U: 'B')

describe "cube_to_hand", ->
it "cube_to_hand", ->
pov = new Pov(new Move("S'"))
expect(pov.cube_to_hand("XYZ:URF")).to.equal("XYZ:LUF")
expect(pov.cube_to_hand("XYZ:Urf")).to.equal("XYZ:Luf")
expect(pov.cube_to_hand(null)).to.equal(null)

describe "hand_to_cube", ->
it "hand_to_cube", ->
pov = new Pov(new Move("S'"))
expect(pov.hand_to_cube("F"), 1).to.equal("F")
expect(pov.hand_to_cube("L"), 1).to.equal("U")

pov = new Pov(new Move("E"))
expect(pov.hand_to_cube("F"), 1).to.equal("L")
expect(pov.hand_to_cube("f"), 1).to.equal("l")

expect(pov.cube_to_hand(null)).to.equal(null)

0 comments on commit 582a7ea

Please sign in to comment.