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 + -
显示快捷键?