cols.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 616 行 · 第 1/2 页
ERL
616 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(cols).-export([start/0, init/0]).%% internal export.-export([make_board_elem/3]).%%======================================================================%% Contents%%=====================%% 1. The actual program%% 2. Graphics%% 3. Data structures and stuff%% 4. Lambdas%%======================================================================-define(COLORS, {red,green,blue,grey,yellow,{66,153,130}}).-define(HIGHFILE, "./cols.high").-define(HEIGHT, 17).-define(LEFT, 50).-define(SIZE, 15).-define(VERSION, "v0.9").-define(WIDTH, 8).-record(state, {bit,board,nextbit,ticks, score=0}).%%----------------------------------------------------------------------%% Consists of three boxes.%%-----------------------------------------------------------------------record(bit, {x,y,topColor, middleColor, bottomColor, top_gsobj,mid_gsobj,bot_gsobj}).%%======================================================================%% 1. The actual program%%======================================================================start() -> spawn_link(cols,init,[]).init() -> make_graphics(), {A,B,C} = erlang:now(), random:seed(A,B,C), NextBit = make_bit(), Board = make_screen_board(), S = #state{bit=make_bit(), board=Board, ticks=update_timer(1), score=make_score(), nextbit=new_bit_xy(NextBit, -2,5)}, gs:config(win, [{map, true}]), loop(S).make_graphics() -> G = gs:start(), H = ?HEIGHT*?SIZE, W = ?WIDTH*?SIZE, BotMargin = 100, gs:create(window, win, G, [{destroy,true},{map, true},{title, "cols"}, {height, H+BotMargin}, {width, W+?LEFT+10}, {bg, grey},{keypress,true}]), gs:create(canvas, can, win, [{bg, black}, {height, H+BotMargin}, {width, W+?LEFT+20}]), gs:create(text, can, [{text, "Next"}, {coords, [{5, 45}]}, {fg, red}]), gs:create(image, help, can, [{coords,[{5,7}]}, {load_gif, dir() ++ "/help.gif"}, {buttonpress,true}]), draw_borders().loop(State) -> receive Event -> loop(update(Event, State)) end.%%----------------------------------------------------------------------%% How fast speed should be doubled%%-----------------------------------------------------------------------define(DBL_TICKS, 300).update_timer(Ticks) -> K = 0.001/?DBL_TICKS, M = 1.001-K, Q = K*Ticks+M, Timeout = round(1/math:log(Q)), timer:send_after(Timeout, self(), fall_timeout), Ticks+1.add_score({ScoreObj, NScore}, DScore) -> NScore2 = NScore + DScore, gs:config(ScoreObj, [{text, io_lib:format("Score: ~w", [NScore2])}]), {ScoreObj, NScore2}. update({gs,_Obj,keypress,_Data, ['Left'|_]}, State) -> #state{bit=Bit, board = Board} = State, #bit{x=X,y=Y} = Bit, if X > 0 -> case is_board_empty(Board, X-1,Y) of true -> State#state{bit=new_bit_xy(Bit, X-1, Y)}; false -> State end; true -> State end;update({gs,_Obj,keypress,_Data, ['Right'|_]}, State) -> #state{bit=Bit, board = Board} = State, #bit{x=X,y=Y} = Bit, if X < ?WIDTH - 1 -> case is_board_empty(Board, X+1, Y) of true -> State#state{bit=new_bit_xy(Bit, X+1, Y)}; false -> State end; true -> State end;update({gs,_Obj,keypress,_Data, ['Up'|_]}, State) -> State#state{bit=shift_bits(State#state.bit)}; update({gs,_Obj,keypress,_Data, [Key|_]}, State) -> case drop_key(Key) of true -> #state{bit=Bit, board=Board, score=Score} = State, #bit{x=X,y=Y} = Bit, {NewX, NewY, NewScore} = drop(X,Y,Score,Board), fasten_bit(State#state{bit=new_bit_xy(Bit,NewX, NewY), score=NewScore}); false -> State end; update(fall_timeout, State) -> #state{bit=Bit, board=Board, ticks = Ticks, score=Score} = State, NewY = Bit#bit.y+1, X = Bit#bit.x, case is_fall_ok(Board, X, NewY) of true -> State#state{bit=new_bit_xy(Bit, X, NewY), ticks=update_timer(Ticks), score=add_score(Score, 1)}; false -> S1 = fasten_bit(State), S1#state{ticks=update_timer(Ticks)} end;update({gs,_,destroy,_,_}, _State) -> exit(normal);update({gs,help,buttonpress,_,_}, State) -> show_help(), State;update(OtherEvent, State) -> ok=io:format("got other! ~w~n", [OtherEvent]), State. drop_key('Down') -> true;drop_key(space) -> true;drop_key(_) -> false.is_board_empty(Board, X, Y) -> case {color_at(Board, X, Y), color_at(Board, X, Y + 1), color_at(Board, X, Y + 2)} of {black, black, black} -> true; _ -> false end.%%----------------------------------------------------------------------%% Returns: NewState%%----------------------------------------------------------------------fasten_bit(State) -> #state{board=Board, bit=Bit, nextbit=NextBit, score=Score} = State, #bit{x=X,y=Y,topColor=C1,middleColor=C2,bottomColor=C3} = Bit, B1 = update_screen_element(Board, X, Y, C1), B2 = update_screen_element(B1, X, Y+1, C2), B3 = update_screen_element(B2, X, Y+2, C3), destroy_bit(Bit), #bit{topColor=NC1,middleColor=NC2,bottomColor=NC3} = NextBit, {B4, ExtraScore} = erase_bits(B3, [{X,Y},{X,Y+1},{X,Y+2}], 0), NewBit = make_bit(NC1,NC2,NC3), case is_board_empty(B4, NewBit#bit.x, NewBit#bit.y) of true -> State#state{score=add_score(Score, ExtraScore), bit=NewBit, nextbit=new_colors(NextBit),board=B4}; false -> {_GsObj,Score2}=State#state.score, highscore:run(Score2,?HIGHFILE), exit(normal) end.%%----------------------------------------------------------------------%% Args: Check: list of {X,Y} to check.%% Returns: {NewBoard, ExtraScore}%%----------------------------------------------------------------------erase_bits(Board, Checks, ExtraScore) -> ElemsToDelete = elems2del(Checks,Board,[]), NDel = length(ElemsToDelete), if NDel > 0 -> Board2 = delete_elems(Board, ElemsToDelete), {NewBoard, NewCheck} = fall_down(Board2, ElemsToDelete), if NDel > 3 -> {B,ES}=erase_bits(NewBoard,NewCheck,ExtraScore+2*NDel), {NewBoard2, NewCheck2} = bonus(B, NewCheck), erase_bits(NewBoard2, NewCheck2, ES); true -> erase_bits(NewBoard, NewCheck, 2*NDel) end; true -> {Board, ExtraScore} end.bonus(Board, Check) -> Cols = collect_bottom_bits(0,Board), NewBoard = randomize_columns(5, Board, Cols), NewCheck = update_check(Check, Cols), {NewBoard, NewCheck}.randomize_columns(0, Board, _) -> Board;randomize_columns(N, Board, Cols) -> NewBoard = randomize_columns(Cols,Board), randomize_columns(N-1, NewBoard, Cols). randomize_columns([],Board) -> Board; randomize_columns([X|Xs],Board) -> flush(), timer:sleep(50), randomize_columns(Xs,update_screen_element(Board,X,?HEIGHT-1,rndColor())).%%----------------------------------------------------------------------%% Returns: NewBoard%%----------------------------------------------------------------------delete_elems(Board, Elems2Del) -> OrgObjs = org_objs(Elems2Del,Board), visual_effect(?SIZE, OrgObjs), NewBoard = update_board(Elems2Del, Board), put_back(OrgObjs), NewBoard.visual_effect(0,_OrgObjs) -> done;visual_effect(Size,OrgObjs) -> set_size(OrgObjs,Size), flush(), timer:sleep(20), visual_effect(Size-1,OrgObjs).set_size([],_Size) -> done;set_size([{GsObj,[{X1,Y1},{_X2,_Y2}]}|T],Size) -> gs:config(GsObj, [{coords, [{X1,Y1},{X1+Size,Y1+Size}]}]), set_size(T,Size).%%----------------------------------------------------------------------%% Note: Loop over columns where something is removed only. (efficiency)%% Returns: {ReversedNewColumns (perhaps shorter), Checks}%% cols:fall_column([a,b,black,black,c,f,black,d,black], 3, 15, [], []).%% should return: {[a,b,c,f,d],[{3,11},{3,12},{3,13}]}%%----------------------------------------------------------------------fall_column([], _X, _Y, ColumnAcc, ChecksAcc) -> {ColumnAcc, ChecksAcc};fall_column([black|Colors], X, Y, ColumnAcc, ChecksAcc) -> case find_box(Colors) of false -> {ColumnAcc, ChecksAcc}; NewColors when list(NewColors) -> fall_one_step(NewColors, X, Y, ColumnAcc, ChecksAcc) end;fall_column([Color|Colors], X, Y, ColumnAcc, ChecksAcc) -> fall_column(Colors, X, Y-1, [Color | ColumnAcc], ChecksAcc).find_box([]) -> false;find_box([black|Colors]) -> find_box(Colors);find_box([Color|Colors]) -> [Color|Colors]. %%----------------------------------------------------------------------%% Enters: ([a,b, , ,c,d], 3, 8, Q) %% Leaves: ([b,a|Q], [ , , ,c,d], 10, [{3,8},{4,9}])%%----------------------------------------------------------------------fall_one_step([], X, Y, ColumnAcc, Checks) -> fall_column([], X, Y, ColumnAcc, Checks);fall_one_step([black|Colors], X, Y, ColumnAcc, Checks) -> fall_column([black|Colors], X, Y, ColumnAcc, Checks);fall_one_step([Color|Colors], X, Y, ColumnAcc, Checks) -> fall_one_step(Colors, X, Y-1, [Color|ColumnAcc],[{X,Y}|Checks]).%%----------------------------------------------------------------------%% Returns: {NewBoard, NewChecks}%%----------------------------------------------------------------------fall_down(Board1, Elems2Del) -> UpDatedCols = updated_cols(Elems2Del, []), fall_column(UpDatedCols, Board1, []).fall_column([], NewBoard, NewChecks) -> {NewBoard, NewChecks};fall_column([X|Xs], BoardAcc, ChecksAcc) ->
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?